mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-15 01:35:25 +00:00
Merge pull request #223 from SyncrowIOT/SP-1600-FE-Single-Batch-Control-Migration
Sp 1600 fe single batch control migration
This commit is contained in:
@ -1,21 +1,27 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
class AcBloc extends Bloc<AcsEvent, AcsState> {
|
class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||||
late AcStatusModel deviceStatus;
|
late AcStatusModel deviceStatus;
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
Timer? _timer;
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
Timer? _countdownTimer;
|
Timer? _countdownTimer;
|
||||||
|
|
||||||
AcBloc({required this.deviceId}) : super(AcsInitialState()) {
|
AcBloc({
|
||||||
|
required this.deviceId,
|
||||||
|
required this.controlDeviceService,
|
||||||
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(AcsInitialState()) {
|
||||||
on<AcFetchDeviceStatusEvent>(_onFetchAcStatus);
|
on<AcFetchDeviceStatusEvent>(_onFetchAcStatus);
|
||||||
on<AcFetchBatchStatusEvent>(_onFetchAcBatchStatus);
|
on<AcFetchBatchStatusEvent>(_onFetchAcBatchStatus);
|
||||||
on<AcControlEvent>(_onAcControl);
|
on<AcControlEvent>(_onAcControl);
|
||||||
@ -34,14 +40,14 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
int scheduledMinutes = 0;
|
int scheduledMinutes = 0;
|
||||||
|
|
||||||
FutureOr<void> _onFetchAcStatus(
|
FutureOr<void> _onFetchAcStatus(
|
||||||
AcFetchDeviceStatusEvent event, Emitter<AcsState> emit) async {
|
AcFetchDeviceStatusEvent event,
|
||||||
|
Emitter<AcsState> emit,
|
||||||
|
) 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) {
|
||||||
// Convert API value to minutes
|
|
||||||
final totalMinutes = deviceStatus.countdown1 * 6;
|
final totalMinutes = deviceStatus.countdown1 * 6;
|
||||||
scheduledHours = totalMinutes ~/ 60;
|
scheduledHours = totalMinutes ~/ 60;
|
||||||
scheduledMinutes = totalMinutes % 60;
|
scheduledMinutes = totalMinutes % 60;
|
||||||
@ -62,30 +68,24 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _listenToChanges(deviceId) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final stream = ref.onValue;
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) async {
|
stream.listen((DatabaseEvent event) async {
|
||||||
if (event.snapshot.value == null) return;
|
if (event.snapshot.value == null) return;
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
|
||||||
}
|
|
||||||
Map<dynamic, dynamic> usersMap =
|
Map<dynamic, dynamic> usersMap =
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
|
||||||
List<Status> statusList = [];
|
List<Status> statusList = [];
|
||||||
|
|
||||||
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);
|
|
||||||
if (!isClosed) {
|
if (!isClosed) {
|
||||||
add(AcStatusUpdated(deviceStatus));
|
add(AcStatusUpdated(deviceStatus));
|
||||||
}
|
}
|
||||||
@ -93,146 +93,44 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAcStatusUpdated(AcStatusUpdated event, Emitter<AcsState> emit) {
|
void _onAcStatusUpdated(
|
||||||
|
AcStatusUpdated event,
|
||||||
|
Emitter<AcsState> emit,
|
||||||
|
) {
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(ACStatusLoaded(status: deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onAcControl(
|
FutureOr<void> _onAcControl(
|
||||||
AcControlEvent event, Emitter<AcsState> emit) async {
|
AcControlEvent event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<AcsState> emit,
|
||||||
|
) async {
|
||||||
_updateLocalValue(event.code, event.value, emit);
|
emit(AcsLoadingState());
|
||||||
|
_updateDeviceFunctionFromCode(event.code, event.value);
|
||||||
emit(ACStatusLoaded(status: deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
isBatch: false,
|
final success = await controlDeviceService.controlDevice(
|
||||||
deviceId: event.deviceId,
|
deviceUuid: event.deviceId,
|
||||||
code: event.code,
|
status: Status(code: event.code, value: event.value),
|
||||||
value: event.value,
|
);
|
||||||
oldValue: oldValue,
|
|
||||||
emit: emit,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
if (!success) {
|
||||||
required dynamic deviceId,
|
emit(const AcsFailedState(error: 'Failed to control device'));
|
||||||
required String code,
|
|
||||||
required dynamic value,
|
|
||||||
required dynamic oldValue,
|
|
||||||
required Emitter<AcsState> emit,
|
|
||||||
required bool isBatch,
|
|
||||||
}) async {
|
|
||||||
late String id;
|
|
||||||
|
|
||||||
if (deviceId is List) {
|
|
||||||
id = deviceId.first;
|
|
||||||
} else {
|
|
||||||
id = deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
_timer = Timer(const Duration(seconds: 1), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (e is DioException && e.response != null) {
|
|
||||||
debugPrint('Error response: ${e.response?.data}');
|
|
||||||
}
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
}
|
||||||
});
|
} catch (e) {
|
||||||
}
|
emit(AcsFailedState(error: e.toString()));
|
||||||
|
|
||||||
void _revertValueAndEmit(
|
|
||||||
String deviceId, String code, dynamic oldValue, Emitter<AcsState> emit) {
|
|
||||||
_updateLocalValue(code, oldValue, emit);
|
|
||||||
emit(ACStatusLoaded(status: deviceStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateLocalValue(String code, dynamic value, Emitter<AcsState> emit) {
|
|
||||||
switch (code) {
|
|
||||||
case 'switch':
|
|
||||||
if (value is bool) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(acSwitch: value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'temp_set':
|
|
||||||
if (value is int) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(tempSet: value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'mode':
|
|
||||||
if (value is String) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(
|
|
||||||
modeString: value,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'level':
|
|
||||||
if (value is String) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(
|
|
||||||
fanSpeedsString: value,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'child_lock':
|
|
||||||
if (value is bool) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(childLock: value);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'countdown_time':
|
|
||||||
if (value is int) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(countdown1: value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
emit(ACStatusLoaded(status: deviceStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _getValueByCode(String code) {
|
|
||||||
switch (code) {
|
|
||||||
case 'switch':
|
|
||||||
return deviceStatus.acSwitch;
|
|
||||||
case 'temp_set':
|
|
||||||
return deviceStatus.tempSet;
|
|
||||||
case 'mode':
|
|
||||||
return deviceStatus.modeString;
|
|
||||||
case 'level':
|
|
||||||
return deviceStatus.fanSpeedsString;
|
|
||||||
case 'child_lock':
|
|
||||||
return deviceStatus.childLock;
|
|
||||||
case 'countdown_time':
|
|
||||||
return deviceStatus.countdown1;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchAcBatchStatus(
|
FutureOr<void> _onFetchAcBatchStatus(
|
||||||
AcFetchBatchStatusEvent event, Emitter<AcsState> emit) async {
|
AcFetchBatchStatusEvent event,
|
||||||
|
Emitter<AcsState> emit,
|
||||||
|
) 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()));
|
||||||
@ -240,25 +138,32 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onAcBatchControl(
|
FutureOr<void> _onAcBatchControl(
|
||||||
AcBatchControlEvent event, Emitter<AcsState> emit) async {
|
AcBatchControlEvent event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<AcsState> emit,
|
||||||
|
) async {
|
||||||
_updateLocalValue(event.code, event.value, emit);
|
emit(AcsLoadingState());
|
||||||
|
_updateDeviceFunctionFromCode(event.code, event.value);
|
||||||
emit(ACStatusLoaded(status: deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
isBatch: true,
|
final success = await batchControlDevicesService.batchControlDevices(
|
||||||
deviceId: event.devicesIds,
|
uuids: event.devicesIds,
|
||||||
code: event.code,
|
code: event.code,
|
||||||
value: event.value,
|
value: event.value,
|
||||||
oldValue: oldValue,
|
);
|
||||||
emit: emit,
|
|
||||||
);
|
if (!success) {
|
||||||
|
emit(const AcsFailedState(error: 'Failed to control devices'));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(AcsFailedState(error: e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFactoryReset(
|
Future<void> _onFactoryReset(
|
||||||
AcFactoryResetEvent event, Emitter<AcsState> emit) async {
|
AcFactoryResetEvent event,
|
||||||
|
Emitter<AcsState> emit,
|
||||||
|
) async {
|
||||||
emit(AcsLoadingState());
|
emit(AcsLoadingState());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
@ -275,9 +180,11 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onClose(OnClose event, Emitter<AcsState> emit) {
|
void _onClose(
|
||||||
|
OnClose event,
|
||||||
|
Emitter<AcsState> emit,
|
||||||
|
) {
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
_timer?.cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleIncreaseTime(IncreaseTimeEvent event, Emitter<AcsState> emit) {
|
void _handleIncreaseTime(IncreaseTimeEvent event, Emitter<AcsState> emit) {
|
||||||
@ -300,7 +207,10 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleDecreaseTime(DecreaseTimeEvent event, Emitter<AcsState> emit) {
|
void _handleDecreaseTime(
|
||||||
|
DecreaseTimeEvent 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 totalMinutes = (scheduledHours * 60) + scheduledMinutes;
|
int totalMinutes = (scheduledHours * 60) + scheduledMinutes;
|
||||||
@ -315,7 +225,9 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleToggleTimer(
|
Future<void> _handleToggleTimer(
|
||||||
ToggleScheduleEvent event, Emitter<AcsState> emit) async {
|
ToggleScheduleEvent event,
|
||||||
|
Emitter<AcsState> emit,
|
||||||
|
) async {
|
||||||
if (state is! ACStatusLoaded) return;
|
if (state is! ACStatusLoaded) return;
|
||||||
final currentState = state as ACStatusLoaded;
|
final currentState = state as ACStatusLoaded;
|
||||||
|
|
||||||
@ -331,37 +243,44 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final scaledValue = totalMinutes ~/ 6;
|
final scaledValue = totalMinutes ~/ 6;
|
||||||
await _runDebounce(
|
final success = await controlDeviceService.controlDevice(
|
||||||
isBatch: false,
|
deviceUuid: deviceId,
|
||||||
deviceId: deviceId,
|
status: Status(code: 'countdown_time', value: scaledValue),
|
||||||
code: 'countdown_time',
|
|
||||||
value: scaledValue,
|
|
||||||
oldValue: scaledValue,
|
|
||||||
emit: emit,
|
|
||||||
);
|
);
|
||||||
_startCountdownTimer(emit);
|
|
||||||
emit(currentState.copyWith(isTimerActive: timerActive));
|
if (success) {
|
||||||
|
_startCountdownTimer(emit);
|
||||||
|
emit(currentState.copyWith(isTimerActive: timerActive));
|
||||||
|
} else {
|
||||||
|
timerActive = false;
|
||||||
|
emit(const AcsFailedState(error: 'Failed to set timer'));
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
timerActive = false;
|
timerActive = false;
|
||||||
emit(AcsFailedState(error: e.toString()));
|
emit(AcsFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await _runDebounce(
|
try {
|
||||||
isBatch: false,
|
final success = await controlDeviceService.controlDevice(
|
||||||
deviceId: deviceId,
|
deviceUuid: deviceId,
|
||||||
code: 'countdown_time',
|
status: Status(code: 'countdown_time', value: 0),
|
||||||
value: 0,
|
);
|
||||||
oldValue: 0,
|
|
||||||
emit: emit,
|
if (success) {
|
||||||
);
|
_countdownTimer?.cancel();
|
||||||
_countdownTimer?.cancel();
|
scheduledHours = 0;
|
||||||
scheduledHours = 0;
|
scheduledMinutes = 0;
|
||||||
scheduledMinutes = 0;
|
emit(currentState.copyWith(
|
||||||
emit(currentState.copyWith(
|
isTimerActive: timerActive,
|
||||||
isTimerActive: timerActive,
|
scheduledHours: 0,
|
||||||
scheduledHours: 0,
|
scheduledMinutes: 0,
|
||||||
scheduledMinutes: 0,
|
));
|
||||||
));
|
} else {
|
||||||
|
emit(const AcsFailedState(error: 'Failed to stop timer'));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(AcsFailedState(error: e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,7 +304,10 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleUpdateTimer(UpdateTimerEvent event, Emitter<AcsState> emit) {
|
void _handleUpdateTimer(
|
||||||
|
UpdateTimerEvent event,
|
||||||
|
Emitter<AcsState> emit,
|
||||||
|
) {
|
||||||
if (state is ACStatusLoaded) {
|
if (state is ACStatusLoaded) {
|
||||||
final currentState = state as ACStatusLoaded;
|
final currentState = state as ACStatusLoaded;
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
@ -400,7 +322,6 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
ApiCountdownValueEvent event, Emitter<AcsState> emit) {
|
ApiCountdownValueEvent event, Emitter<AcsState> emit) {
|
||||||
if (state is ACStatusLoaded) {
|
if (state is ACStatusLoaded) {
|
||||||
final totalMinutes = event.apiValue * 6;
|
final totalMinutes = event.apiValue * 6;
|
||||||
final scheduledHours = totalMinutes ~/ 60;
|
|
||||||
scheduledMinutes = totalMinutes % 60;
|
scheduledMinutes = totalMinutes % 60;
|
||||||
_startCountdownTimer(
|
_startCountdownTimer(
|
||||||
emit,
|
emit,
|
||||||
@ -409,6 +330,43 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _updateDeviceFunctionFromCode(String code, dynamic value) {
|
||||||
|
switch (code) {
|
||||||
|
case 'switch':
|
||||||
|
if (value is bool) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(acSwitch: value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'temp_set':
|
||||||
|
if (value is int) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(tempSet: value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'mode':
|
||||||
|
if (value is String) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(modeString: value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'level':
|
||||||
|
if (value is String) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(fanSpeedsString: value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'child_lock':
|
||||||
|
if (value is bool) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(childLock: value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'countdown_time':
|
||||||
|
if (value is int) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(countdown1: value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() {
|
Future<void> close() {
|
||||||
add(OnClose());
|
add(OnClose());
|
||||||
|
18
lib/pages/device_managment/ac/factories/ac_bloc_factory.dart
Normal file
18
lib/pages/device_managment/ac/factories/ac_bloc_factory.dart
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
|
||||||
|
abstract final class AcBlocFactory {
|
||||||
|
const AcBlocFactory._();
|
||||||
|
|
||||||
|
static AcBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return AcBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -3,12 +3,12 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/ac/factories/ac_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/view/batch_control_list/batch_ac_mode.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/view/batch_control_list/batch_ac_mode.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/view/batch_control_list/batch_current_temp.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/view/batch_control_list/batch_current_temp.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/view/batch_control_list/batch_fan_speed.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/view/batch_control_list/batch_fan_speed.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/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.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';
|
||||||
@ -26,8 +26,9 @@ class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayo
|
|||||||
final isLarge = isLargeScreenSize(context);
|
final isLarge = isLargeScreenSize(context);
|
||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) => AcBlocFactory.create(
|
||||||
AcBloc(deviceId: devicesIds.first)..add(AcFetchBatchStatusEvent(devicesIds)),
|
deviceId: devicesIds.first,
|
||||||
|
)..add(AcFetchBatchStatusEvent(devicesIds)),
|
||||||
child: BlocBuilder<AcBloc, AcsState>(
|
child: BlocBuilder<AcBloc, AcsState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is ACStatusLoaded) {
|
if (state is ACStatusLoaded) {
|
||||||
|
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/ac/factories/ac_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/ac_mode.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/ac_mode.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/current_temp.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/current_temp.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/fan_speed.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/fan_speed.dart';
|
||||||
@ -24,8 +25,9 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => AcBloc(deviceId: device.uuid!)
|
create: (context) => AcBlocFactory.create(
|
||||||
..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
deviceId: device.uuid!,
|
||||||
|
)..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
||||||
child: BlocBuilder<AcBloc, AcsState>(
|
child: BlocBuilder<AcBloc, AcsState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final acBloc = BlocProvider.of<AcBloc>(context);
|
final acBloc = BlocProvider.of<AcBloc>(context);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.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';
|
||||||
@ -7,14 +5,21 @@ import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_e
|
|||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/help_description.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/help_description.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
late CeilingSensorModel deviceStatus;
|
late CeilingSensorModel deviceStatus;
|
||||||
Timer? _timer;
|
|
||||||
|
|
||||||
CeilingSensorBloc({required this.deviceId}) : super(CeilingInitialState()) {
|
CeilingSensorBloc({
|
||||||
|
required this.deviceId,
|
||||||
|
required this.controlDeviceService,
|
||||||
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(CeilingInitialState()) {
|
||||||
on<CeilingInitialEvent>(_fetchCeilingSensorStatus);
|
on<CeilingInitialEvent>(_fetchCeilingSensorStatus);
|
||||||
on<CeilingFetchDeviceStatusEvent>(_fetchCeilingSensorBatchControl);
|
on<CeilingFetchDeviceStatusEvent>(_fetchCeilingSensorBatchControl);
|
||||||
on<CeilingChangeValueEvent>(_changeValue);
|
on<CeilingChangeValueEvent>(_changeValue);
|
||||||
@ -26,35 +31,34 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _fetchCeilingSensorStatus(
|
Future<void> _fetchCeilingSensorStatus(
|
||||||
CeilingInitialEvent event, Emitter<CeilingSensorState> emit) async {
|
CeilingInitialEvent event,
|
||||||
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(CeilingLoadingInitialState());
|
emit(CeilingLoadingInitialState());
|
||||||
try {
|
try {
|
||||||
var response =
|
final response = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
|
||||||
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
_listenToChanges(event.deviceId);
|
_listenToChanges(event.deviceId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(CeilingFailedState(error: e.toString()));
|
emit(CeilingFailedState(error: e.toString()));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _listenToChanges(String deviceId) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final stream = ref.onValue;
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
stream.listen((DatabaseEvent event) {
|
||||||
Map<dynamic, dynamic> usersMap =
|
if (event.snapshot.value == null) return;
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
|
||||||
|
final usersMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
final statusList = <Status>[];
|
||||||
|
|
||||||
List<Status> statusList = [];
|
|
||||||
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 = CeilingSensorModel.fromJson(statusList);
|
deviceStatus = CeilingSensorModel.fromJson(statusList);
|
||||||
@ -65,149 +69,127 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(StatusUpdated event, Emitter<CeilingSensorState> emit) {
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event,
|
||||||
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) {
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _changeValue(
|
Future<void> _changeValue(
|
||||||
CeilingChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
|
CeilingChangeValueEvent event,
|
||||||
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
||||||
if (event.code == 'sensitivity') {
|
_updateDeviceFunctionFromCode(event.code, event.value);
|
||||||
deviceStatus.sensitivity = event.value;
|
|
||||||
} else if (event.code == 'none_body_time') {
|
|
||||||
deviceStatus.noBodyTime = event.value;
|
|
||||||
} else if (event.code == 'moving_max_dis') {
|
|
||||||
deviceStatus.maxDistance = event.value;
|
|
||||||
} else if (event.code == 'scene') {
|
|
||||||
deviceStatus.spaceType = getSpaceType(event.value);
|
|
||||||
}
|
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
await _runDeBouncer(
|
|
||||||
deviceId: deviceId,
|
try {
|
||||||
code: event.code,
|
await controlDeviceService.controlDevice(
|
||||||
value: event.value,
|
deviceUuid: deviceId,
|
||||||
emit: emit,
|
status: Status(code: event.code, value: event.value),
|
||||||
isBatch: false,
|
);
|
||||||
);
|
} catch (e) {
|
||||||
|
emit(CeilingFailedState(error: e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(
|
Future<void> _onBatchControl(
|
||||||
CeilingBatchControlEvent event, Emitter<CeilingSensorState> emit) async {
|
CeilingBatchControlEvent event,
|
||||||
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
||||||
if (event.code == 'sensitivity') {
|
_updateDeviceFunctionFromCode(event.code, event.value);
|
||||||
deviceStatus.sensitivity = event.value;
|
|
||||||
} else if (event.code == 'none_body_time') {
|
|
||||||
deviceStatus.noBodyTime = event.value;
|
|
||||||
} else if (event.code == 'moving_max_dis') {
|
|
||||||
deviceStatus.maxDistance = event.value;
|
|
||||||
} else if (event.code == 'scene') {
|
|
||||||
deviceStatus.spaceType = getSpaceType(event.value);
|
|
||||||
}
|
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
await _runDeBouncer(
|
|
||||||
deviceId: event.deviceIds,
|
|
||||||
code: event.code,
|
|
||||||
value: event.value,
|
|
||||||
emit: emit,
|
|
||||||
isBatch: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_runDeBouncer({
|
try {
|
||||||
required dynamic deviceId,
|
final success = await batchControlDevicesService.batchControlDevices(
|
||||||
required String code,
|
uuids: event.deviceIds,
|
||||||
required dynamic value,
|
code: event.code,
|
||||||
required Emitter<CeilingSensorState> emit,
|
value: event.value,
|
||||||
required bool isBatch,
|
);
|
||||||
}) {
|
|
||||||
late String id;
|
|
||||||
|
|
||||||
if (deviceId is List) {
|
if (!success) {
|
||||||
id = deviceId.first;
|
emit(const CeilingFailedState(error: 'Failed to control devices'));
|
||||||
} else {
|
|
||||||
id = deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
_timer = Timer(const Duration(seconds: 1), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
add(CeilingInitialEvent(id));
|
|
||||||
}
|
|
||||||
if (response == true && code == 'scene') {
|
|
||||||
emit(CeilingLoadingInitialState());
|
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
|
||||||
add(CeilingInitialEvent(id));
|
|
||||||
}
|
|
||||||
} catch (_) {
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
add(CeilingInitialEvent(id));
|
|
||||||
}
|
}
|
||||||
});
|
} catch (e) {
|
||||||
|
emit(CeilingFailedState(error: e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _getDeviceReports(GetCeilingDeviceReportsEvent event,
|
void _updateDeviceFunctionFromCode(String code, dynamic value) {
|
||||||
Emitter<CeilingSensorState> emit) async {
|
switch (code) {
|
||||||
|
case 'sensitivity':
|
||||||
|
deviceStatus.sensitivity = value;
|
||||||
|
break;
|
||||||
|
case 'none_body_time':
|
||||||
|
deviceStatus.noBodyTime = value;
|
||||||
|
break;
|
||||||
|
case 'moving_max_dis':
|
||||||
|
deviceStatus.maxDistance = value;
|
||||||
|
break;
|
||||||
|
case 'scene':
|
||||||
|
deviceStatus.spaceType = getSpaceType(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _getDeviceReports(
|
||||||
|
GetCeilingDeviceReportsEvent event,
|
||||||
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) async {
|
||||||
if (event.code.isEmpty) {
|
if (event.code.isEmpty) {
|
||||||
emit(ShowCeilingDescriptionState(description: reportString));
|
emit(ShowCeilingDescriptionState(description: reportString));
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
emit(CeilingReportsLoadingState());
|
|
||||||
// final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch;
|
|
||||||
// final to = DateTime.now().millisecondsSinceEpoch;
|
|
||||||
|
|
||||||
try {
|
emit(CeilingReportsLoadingState());
|
||||||
// await DevicesManagementApi.getDeviceReportsByDate(deviceId, event.code, from.toString(), to.toString())
|
try {
|
||||||
await DevicesManagementApi.getDeviceReports(deviceId, event.code)
|
final value = await DevicesManagementApi.getDeviceReports(
|
||||||
.then((value) {
|
deviceId,
|
||||||
emit(CeilingReportsState(deviceReport: value));
|
event.code,
|
||||||
});
|
);
|
||||||
} catch (e) {
|
emit(CeilingReportsState(deviceReport: value));
|
||||||
emit(CeilingReportsFailedState(error: e.toString()));
|
} catch (e) {
|
||||||
return;
|
emit(CeilingReportsFailedState(error: e.toString()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showDescription(
|
void _showDescription(
|
||||||
ShowCeilingDescriptionEvent event, Emitter<CeilingSensorState> emit) {
|
ShowCeilingDescriptionEvent event,
|
||||||
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) {
|
||||||
emit(ShowCeilingDescriptionState(description: event.description));
|
emit(ShowCeilingDescriptionState(description: event.description));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _backToGridView(
|
void _backToGridView(
|
||||||
BackToCeilingGridViewEvent event, Emitter<CeilingSensorState> emit) {
|
BackToCeilingGridViewEvent event,
|
||||||
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) {
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _fetchCeilingSensorBatchControl(
|
Future<void> _fetchCeilingSensorBatchControl(
|
||||||
CeilingFetchDeviceStatusEvent event,
|
CeilingFetchDeviceStatusEvent event,
|
||||||
Emitter<CeilingSensorState> emit) async {
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(CeilingLoadingInitialState());
|
emit(CeilingLoadingInitialState());
|
||||||
try {
|
try {
|
||||||
var response =
|
final response = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
|
||||||
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
||||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(CeilingFailedState(error: e.toString()));
|
emit(CeilingFailedState(error: e.toString()));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFactoryReset(
|
Future<void> _onFactoryReset(
|
||||||
CeilingFactoryResetEvent event, Emitter<CeilingSensorState> emit) async {
|
CeilingFactoryResetEvent event,
|
||||||
|
Emitter<CeilingSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
|
||||||
|
abstract final class CeilingSensorBlocFactory {
|
||||||
|
const CeilingSensorBlocFactory._();
|
||||||
|
|
||||||
|
static CeilingSensorBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return CeilingSensorBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,9 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_re
|
|||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/factories/ceiling_sensor_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_space_type.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_space_type.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_update_data.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_update_data.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presense_nobody_time.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presense_nobody_time.dart';
|
||||||
@ -23,8 +23,9 @@ class CeilingSensorBatchControlView extends StatelessWidget with HelperResponsiv
|
|||||||
final isLarge = isLargeScreenSize(context);
|
final isLarge = isLargeScreenSize(context);
|
||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => CeilingSensorBloc(deviceId: devicesIds.first)
|
create: (context) => CeilingSensorBlocFactory.create(
|
||||||
..add(CeilingFetchDeviceStatusEvent(devicesIds)),
|
deviceId: devicesIds.first,
|
||||||
|
)..add(CeilingFetchDeviceStatusEvent(devicesIds)),
|
||||||
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
|
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is CeilingLoadingInitialState || state is CeilingReportsLoadingState) {
|
if (state is CeilingLoadingInitialState || state is CeilingReportsLoadingState) {
|
||||||
@ -110,7 +111,6 @@ class CeilingSensorBatchControlView extends StatelessWidget with HelperResponsiv
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// FirmwareUpdateWidget(deviceId: devicesIds.first, version: 4),
|
|
||||||
FactoryResetWidget(
|
FactoryResetWidget(
|
||||||
callFactoryReset: () {
|
callFactoryReset: () {
|
||||||
context.read<CeilingSensorBloc>().add(
|
context.read<CeilingSensorBloc>().add(
|
||||||
|
@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
|||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/factories/ceiling_sensor_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
|
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_display_data.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_display_data.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_space_type.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_space_type.dart';
|
||||||
@ -28,8 +29,9 @@ class CeilingSensorControlsView extends StatelessWidget
|
|||||||
final isLarge = isLargeScreenSize(context);
|
final isLarge = isLargeScreenSize(context);
|
||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => CeilingSensorBloc(deviceId: device.uuid ?? '')
|
create: (context) => CeilingSensorBlocFactory.create(
|
||||||
..add(CeilingInitialEvent(device.uuid ?? '')),
|
deviceId: device.uuid ?? '',
|
||||||
|
)..add(CeilingInitialEvent(device.uuid ?? '')),
|
||||||
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
|
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is CeilingLoadingInitialState ||
|
if (state is CeilingLoadingInitialState ||
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.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/curtain/bloc/curtain_event.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_state.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_state.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
||||||
late bool deviceStatus;
|
late bool deviceStatus;
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
Timer? _timer;
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
CurtainBloc({required this.deviceId}) : super(CurtainInitial()) {
|
CurtainBloc({
|
||||||
|
required this.deviceId,
|
||||||
|
required this.controlDeviceService,
|
||||||
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(CurtainInitial()) {
|
||||||
on<CurtainFetchDeviceStatus>(_onFetchDeviceStatus);
|
on<CurtainFetchDeviceStatus>(_onFetchDeviceStatus);
|
||||||
on<CurtainFetchBatchStatus>(_onFetchBatchStatus);
|
on<CurtainFetchBatchStatus>(_onFetchBatchStatus);
|
||||||
on<CurtainControl>(_onCurtainControl);
|
on<CurtainControl>(_onCurtainControl);
|
||||||
@ -20,32 +28,31 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchDeviceStatus(
|
Future<void> _onFetchDeviceStatus(
|
||||||
CurtainFetchDeviceStatus event, Emitter<CurtainState> emit) async {
|
CurtainFetchDeviceStatus event,
|
||||||
|
Emitter<CurtainState> emit,
|
||||||
|
) async {
|
||||||
emit(CurtainStatusLoading());
|
emit(CurtainStatusLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
_listenToChanges(event.deviceId, emit);
|
||||||
_listenToChanges(event.deviceId);
|
|
||||||
deviceStatus = _checkStatus(status.status[0].value);
|
deviceStatus = _checkStatus(status.status[0].value);
|
||||||
|
|
||||||
emit(CurtainStatusLoaded(deviceStatus));
|
emit(CurtainStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(CurtainError(e.toString()));
|
emit(CurtainError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _listenToChanges(String deviceId) {
|
void _listenToChanges(String deviceId, Emitter<CurtainState> emit) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final stream = ref.onValue;
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
stream.listen((DatabaseEvent event) {
|
||||||
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
||||||
List<Status> statusList = [];
|
final statusList = <Status>[];
|
||||||
if (data['status'] != null) {
|
if (data['status'] != null) {
|
||||||
for (var element in data['status']) {
|
for (var element in data['status']) {
|
||||||
statusList.add(
|
statusList.add(
|
||||||
@ -57,7 +64,7 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (statusList.isNotEmpty) {
|
if (statusList.isNotEmpty) {
|
||||||
bool newStatus = _checkStatus(statusList[0].value);
|
final newStatus = _checkStatus(statusList[0].value);
|
||||||
if (newStatus != deviceStatus) {
|
if (newStatus != deviceStatus) {
|
||||||
deviceStatus = newStatus;
|
deviceStatus = newStatus;
|
||||||
if (!isClosed) {
|
if (!isClosed) {
|
||||||
@ -71,76 +78,32 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(StatusUpdated event, Emitter<CurtainState> emit) {
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event,
|
||||||
|
Emitter<CurtainState> emit,
|
||||||
|
) {
|
||||||
emit(CurtainStatusLoading());
|
emit(CurtainStatusLoading());
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(CurtainStatusLoaded(deviceStatus));
|
emit(CurtainStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onCurtainControl(
|
Future<void> _onCurtainControl(
|
||||||
CurtainControl event, Emitter<CurtainState> emit) async {
|
CurtainControl event,
|
||||||
final oldValue = deviceStatus;
|
Emitter<CurtainState> emit,
|
||||||
|
) async {
|
||||||
|
emit(CurtainStatusLoading());
|
||||||
_updateLocalValue(event.value, emit);
|
_updateLocalValue(event.value, emit);
|
||||||
|
|
||||||
emit(CurtainStatusLoaded(deviceStatus));
|
try {
|
||||||
|
final controlValue = event.value ? 'open' : 'close';
|
||||||
await _runDebounce(
|
await controlDeviceService.controlDevice(
|
||||||
deviceId: event.deviceId,
|
deviceUuid: event.deviceId,
|
||||||
code: event.code,
|
status: Status(code: event.code, value: controlValue),
|
||||||
value: event.value,
|
);
|
||||||
oldValue: oldValue,
|
} catch (e) {
|
||||||
emit: emit,
|
_updateLocalValue(!event.value, emit);
|
||||||
isBatch: false,
|
emit(CurtainControlError(e.toString()));
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
|
||||||
required dynamic deviceId,
|
|
||||||
required String code,
|
|
||||||
required bool value,
|
|
||||||
required bool oldValue,
|
|
||||||
required Emitter<CurtainState> emit,
|
|
||||||
required bool isBatch,
|
|
||||||
}) async {
|
|
||||||
late String id;
|
|
||||||
|
|
||||||
if (deviceId is List) {
|
|
||||||
id = deviceId.first;
|
|
||||||
} else {
|
|
||||||
id = deviceId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
_timer = Timer(const Duration(seconds: 1), () async {
|
|
||||||
try {
|
|
||||||
final controlValue = value ? 'open' : 'close';
|
|
||||||
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, controlValue);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: controlValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(id, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValueAndEmit(id, oldValue, emit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValueAndEmit(
|
|
||||||
String deviceId, bool oldValue, Emitter<CurtainState> emit) {
|
|
||||||
_updateLocalValue(oldValue, emit);
|
|
||||||
emit(CurtainStatusLoaded(deviceStatus));
|
|
||||||
emit(const CurtainControlError('Failed to control the device.'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateLocalValue(bool value, Emitter<CurtainState> emit) {
|
void _updateLocalValue(bool value, Emitter<CurtainState> emit) {
|
||||||
@ -152,41 +115,44 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
|||||||
return command.toLowerCase() == 'open';
|
return command.toLowerCase() == 'open';
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchBatchStatus(
|
Future<void> _onFetchBatchStatus(
|
||||||
CurtainFetchBatchStatus event, Emitter<CurtainState> emit) async {
|
CurtainFetchBatchStatus event,
|
||||||
|
Emitter<CurtainState> emit,
|
||||||
|
) async {
|
||||||
emit(CurtainStatusLoading());
|
emit(CurtainStatusLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
|
||||||
|
|
||||||
deviceStatus = _checkStatus(status.status[0].value);
|
deviceStatus = _checkStatus(status.status[0].value);
|
||||||
|
|
||||||
emit(CurtainStatusLoaded(deviceStatus));
|
emit(CurtainStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(CurtainError(e.toString()));
|
emit(CurtainError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onCurtainBatchControl(
|
Future<void> _onCurtainBatchControl(
|
||||||
CurtainBatchControl event, Emitter<CurtainState> emit) async {
|
CurtainBatchControl event,
|
||||||
final oldValue = deviceStatus;
|
Emitter<CurtainState> emit,
|
||||||
|
) async {
|
||||||
|
emit(CurtainStatusLoading());
|
||||||
_updateLocalValue(event.value, emit);
|
_updateLocalValue(event.value, emit);
|
||||||
|
|
||||||
emit(CurtainStatusLoaded(deviceStatus));
|
try {
|
||||||
|
final controlValue = event.value ? 'open' : 'stop';
|
||||||
await _runDebounce(
|
await batchControlDevicesService.batchControlDevices(
|
||||||
deviceId: event.devicesIds,
|
uuids: event.devicesIds,
|
||||||
code: event.code,
|
code: event.code,
|
||||||
value: event.value,
|
value: controlValue,
|
||||||
oldValue: oldValue,
|
);
|
||||||
emit: emit,
|
} catch (e) {
|
||||||
isBatch: true,
|
_updateLocalValue(!event.value, emit);
|
||||||
);
|
emit(CurtainControlError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFactoryReset(
|
Future<void> _onFactoryReset(
|
||||||
CurtainFactoryReset event, Emitter<CurtainState> emit) async {
|
CurtainFactoryReset event,
|
||||||
|
Emitter<CurtainState> emit,
|
||||||
|
) async {
|
||||||
emit(CurtainStatusLoading());
|
emit(CurtainStatusLoading());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
|
||||||
|
abstract final class CurtainBlocFactory {
|
||||||
|
const CurtainBlocFactory._();
|
||||||
|
|
||||||
|
static CurtainBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return CurtainBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_re
|
|||||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_state.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/curtain/factories/curtain_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
@ -18,7 +19,7 @@ class CurtainBatchStatusView extends StatelessWidget with HelperResponsiveLayout
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
CurtainBloc(deviceId: devicesIds.first)..add(CurtainFetchBatchStatus(devicesIds)),
|
CurtainBlocFactory.create(deviceId: devicesIds.first)..add(CurtainFetchBatchStatus(devicesIds)),
|
||||||
child: BlocBuilder<CurtainBloc, CurtainState>(
|
child: BlocBuilder<CurtainBloc, CurtainState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is CurtainStatusLoading) {
|
if (state is CurtainStatusLoading) {
|
||||||
|
@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/common/curtain_toggle.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_state.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/curtain/factories/curtain_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class CurtainStatusControlsView extends StatelessWidget
|
class CurtainStatusControlsView extends StatelessWidget
|
||||||
@ -15,7 +16,7 @@ class CurtainStatusControlsView extends StatelessWidget
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => CurtainBloc(deviceId: deviceId)
|
create: (context) => CurtainBlocFactory.create(deviceId: deviceId)
|
||||||
..add(CurtainFetchDeviceStatus(deviceId)),
|
..add(CurtainFetchDeviceStatus(deviceId)),
|
||||||
child: BlocBuilder<CurtainBloc, CurtainState>(
|
child: BlocBuilder<CurtainBloc, CurtainState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/services/batch_control_devices_service.dart';
|
||||||
|
import 'package:syncrow_web/services/control_device_service.dart';
|
||||||
|
|
||||||
|
abstract final class DeviceBlocDependenciesFactory {
|
||||||
|
const DeviceBlocDependenciesFactory._();
|
||||||
|
|
||||||
|
static ControlDeviceService createControlDeviceService() {
|
||||||
|
return DebouncedControlDeviceService(
|
||||||
|
decoratee: RemoteControlDeviceService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BatchControlDevicesService createBatchControlDevicesService() {
|
||||||
|
return DebouncedBatchControlDevicesService(
|
||||||
|
decoratee: RemoteBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/flush_mounted_presence_sensor/bloc/flush_mounted_presence_sensor_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/flush_mounted_presence_sensor/bloc/flush_mounted_presence_sensor_bloc.dart';
|
||||||
import 'package:syncrow_web/services/batch_control_devices_service.dart';
|
|
||||||
import 'package:syncrow_web/services/control_device_service.dart';
|
|
||||||
|
|
||||||
abstract final class FlushMountedPresenceSensorBlocFactory {
|
abstract final class FlushMountedPresenceSensorBlocFactory {
|
||||||
const FlushMountedPresenceSensorBlocFactory._();
|
const FlushMountedPresenceSensorBlocFactory._();
|
||||||
@ -10,12 +9,8 @@ abstract final class FlushMountedPresenceSensorBlocFactory {
|
|||||||
}) {
|
}) {
|
||||||
return FlushMountedPresenceSensorBloc(
|
return FlushMountedPresenceSensorBloc(
|
||||||
deviceId: deviceId,
|
deviceId: deviceId,
|
||||||
controlDeviceService: DebouncedControlDeviceService(
|
controlDeviceService: DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
decoratee: RemoteControlDeviceService(),
|
batchControlDevicesService: DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
),
|
|
||||||
batchControlDevicesService: DebouncedBatchControlDevicesService(
|
|
||||||
decoratee: RemoteBatchControlDevicesService(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.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/one_g_glass_switch/models/once_gang_glass_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/models/once_gang_glass_status_model.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
part 'one_gang_glass_switch_event.dart';
|
part 'one_gang_glass_switch_event.dart';
|
||||||
@ -13,13 +15,16 @@ part 'one_gang_glass_switch_state.dart';
|
|||||||
|
|
||||||
class OneGangGlassSwitchBloc
|
class OneGangGlassSwitchBloc
|
||||||
extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
|
extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
|
||||||
OneGangGlassStatusModel deviceStatus;
|
late OneGangGlassStatusModel deviceStatus;
|
||||||
Timer? _timer;
|
final String deviceId;
|
||||||
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
OneGangGlassSwitchBloc({required String deviceId})
|
OneGangGlassSwitchBloc({
|
||||||
: deviceStatus = OneGangGlassStatusModel(
|
required this.deviceId,
|
||||||
uuid: deviceId, switch1: false, countDown: 0),
|
required this.controlDeviceService,
|
||||||
super(OneGangGlassSwitchInitial()) {
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(OneGangGlassSwitchInitial()) {
|
||||||
on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||||
on<OneGangGlassSwitchControl>(_onControl);
|
on<OneGangGlassSwitchControl>(_onControl);
|
||||||
on<OneGangGlassSwitchBatchControl>(_onBatchControl);
|
on<OneGangGlassSwitchBatchControl>(_onBatchControl);
|
||||||
@ -28,160 +33,140 @@ class OneGangGlassSwitchBloc
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDeviceStatus(OneGangGlassSwitchFetchDeviceEvent event,
|
Future<void> _onFetchDeviceStatus(
|
||||||
Emitter<OneGangGlassSwitchState> emit) async {
|
OneGangGlassSwitchFetchDeviceEvent event,
|
||||||
|
Emitter<OneGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
emit(OneGangGlassSwitchLoading());
|
emit(OneGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
_listenToChanges(event.deviceId, emit);
|
||||||
_listenToChanges(event.deviceId);
|
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
deviceStatus =
|
|
||||||
OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(OneGangGlassSwitchError(e.toString()));
|
emit(OneGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _listenToChanges(
|
||||||
|
String deviceId,
|
||||||
|
Emitter<OneGangGlassSwitchState> emit,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final stream = ref.onValue;
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
stream.listen((DatabaseEvent event) {
|
||||||
Map<dynamic, dynamic> usersMap =
|
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
if (data == null) return;
|
||||||
|
|
||||||
List<Status> statusList = [];
|
final statusList = <Status>[];
|
||||||
usersMap['status'].forEach((element) {
|
if (data['status'] != null) {
|
||||||
statusList
|
for (var element in data['status']) {
|
||||||
.add(Status(code: element['code'], value: element['value']));
|
statusList.add(
|
||||||
});
|
Status(
|
||||||
|
code: element['code'].toString(),
|
||||||
deviceStatus = OneGangGlassStatusModel.fromJson(
|
value: element['value'].toString(),
|
||||||
usersMap['productUuid'], statusList);
|
),
|
||||||
if (!isClosed) {
|
);
|
||||||
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(
|
||||||
StatusUpdated event, Emitter<OneGangGlassSwitchState> emit) {
|
StatusUpdated event,
|
||||||
|
Emitter<OneGangGlassSwitchState> emit,
|
||||||
|
) {
|
||||||
|
emit(OneGangGlassSwitchLoading());
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onControl(OneGangGlassSwitchControl event,
|
Future<void> _onControl(
|
||||||
Emitter<OneGangGlassSwitchState> emit) async {
|
OneGangGlassSwitchControl event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<OneGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(OneGangGlassSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
|
||||||
deviceId: event.deviceId,
|
|
||||||
code: event.code,
|
|
||||||
value: event.value,
|
|
||||||
oldValue: oldValue,
|
|
||||||
emit: emit,
|
|
||||||
isBatch: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event,
|
|
||||||
Emitter<OneGangGlassSwitchState> emit) async {
|
|
||||||
emit(OneGangGlassSwitchLoading());
|
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi()
|
await controlDeviceService.controlDevice(
|
||||||
.factoryReset(event.factoryReset, event.deviceId);
|
deviceUuid: event.deviceId,
|
||||||
if (!response) {
|
status: Status(code: event.code, value: event.value),
|
||||||
emit(OneGangGlassSwitchError('Failed to reset device'));
|
);
|
||||||
} else {
|
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
_updateLocalValue(event.code, !event.value);
|
||||||
emit(OneGangGlassSwitchError(e.toString()));
|
emit(OneGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event,
|
Future<void> _onBatchControl(
|
||||||
Emitter<OneGangGlassSwitchState> emit) async {
|
OneGangGlassSwitchBatchControl event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<OneGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(OneGangGlassSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
deviceId: event.deviceIds,
|
await batchControlDevicesService.batchControlDevices(
|
||||||
code: event.code,
|
uuids: event.deviceIds,
|
||||||
value: event.value,
|
code: event.code,
|
||||||
oldValue: oldValue,
|
value: event.value,
|
||||||
emit: emit,
|
);
|
||||||
isBatch: true,
|
} catch (e) {
|
||||||
);
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(OneGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(
|
Future<void> _onFetchBatchStatus(
|
||||||
OneGangGlassSwitchFetchBatchStatusEvent event,
|
OneGangGlassSwitchFetchBatchStatusEvent event,
|
||||||
Emitter<OneGangGlassSwitchState> emit) async {
|
Emitter<OneGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
emit(OneGangGlassSwitchLoading());
|
emit(OneGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
deviceStatus =
|
||||||
deviceStatus = OneGangGlassStatusModel.fromJson(
|
OneGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
|
||||||
event.deviceIds.first, status.status);
|
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(OneGangGlassSwitchError(e.toString()));
|
emit(OneGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
Future<void> _onFactoryReset(
|
||||||
required dynamic deviceId,
|
OneGangGlassFactoryResetEvent event,
|
||||||
required String code,
|
Emitter<OneGangGlassSwitchState> emit,
|
||||||
required bool value,
|
) async {
|
||||||
required bool oldValue,
|
emit(OneGangGlassSwitchLoading());
|
||||||
required Emitter<OneGangGlassSwitchState> emit,
|
try {
|
||||||
required bool isBatch,
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
}) async {
|
event.factoryReset,
|
||||||
late String id;
|
event.deviceId,
|
||||||
if (deviceId is List) {
|
);
|
||||||
id = deviceId.first;
|
if (!response) {
|
||||||
} else {
|
emit(OneGangGlassSwitchError('Failed to reset device'));
|
||||||
id = deviceId;
|
} else {
|
||||||
}
|
add(OneGangGlassSwitchFetchDeviceEvent(event.deviceId));
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
}
|
||||||
});
|
} catch (e) {
|
||||||
}
|
emit(OneGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
|
||||||
Emitter<OneGangGlassSwitchState> emit) {
|
|
||||||
_updateLocalValue(code, oldValue);
|
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateLocalValue(String code, bool value) {
|
void _updateLocalValue(String code, bool value) {
|
||||||
@ -189,19 +174,4 @@ class OneGangGlassSwitchBloc
|
|||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _getValueByCode(String code) {
|
|
||||||
switch (code) {
|
|
||||||
case 'switch_1':
|
|
||||||
return deviceStatus.switch1;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() {
|
|
||||||
_timer?.cancel();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart';
|
||||||
|
|
||||||
|
abstract final class OneGangGlassSwitchBlocFactory {
|
||||||
|
const OneGangGlassSwitchBlocFactory._();
|
||||||
|
|
||||||
|
static OneGangGlassSwitchBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return OneGangGlassSwitchBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.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/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/factories/one_gang_glass_switch_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/models/once_gang_glass_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/models/once_gang_glass_status_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ class OneGangGlassSwitchBatchControlView extends StatelessWidget with HelperResp
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => OneGangGlassSwitchBloc(deviceId: deviceIds.first)
|
create: (context) => OneGangGlassSwitchBlocFactory.create(deviceId: deviceIds.first)
|
||||||
..add(OneGangGlassSwitchFetchBatchStatusEvent(deviceIds)),
|
..add(OneGangGlassSwitchFetchBatchStatusEvent(deviceIds)),
|
||||||
child: BlocBuilder<OneGangGlassSwitchBloc, OneGangGlassSwitchState>(
|
child: BlocBuilder<OneGangGlassSwitchBloc, OneGangGlassSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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:syncrow_web/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/factories/one_gang_glass_switch_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/models/once_gang_glass_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/models/once_gang_glass_status_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
@ -9,13 +10,13 @@ import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_la
|
|||||||
class OneGangGlassSwitchControlView extends StatelessWidget with HelperResponsiveLayout {
|
class OneGangGlassSwitchControlView extends StatelessWidget with HelperResponsiveLayout {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
|
||||||
const OneGangGlassSwitchControlView({required this.deviceId, Key? key}) : super(key: key);
|
const OneGangGlassSwitchControlView({required this.deviceId, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
OneGangGlassSwitchBloc(deviceId: deviceId)..add(OneGangGlassSwitchFetchDeviceEvent(deviceId)),
|
OneGangGlassSwitchBlocFactory.create(deviceId: deviceId)..add(OneGangGlassSwitchFetchDeviceEvent(deviceId)),
|
||||||
child: BlocBuilder<OneGangGlassSwitchBloc, OneGangGlassSwitchState>(
|
child: BlocBuilder<OneGangGlassSwitchBloc, OneGangGlassSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is OneGangGlassSwitchLoading) {
|
if (state is OneGangGlassSwitchLoading) {
|
||||||
|
@ -6,12 +6,21 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_sta
|
|||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
class WallLightSwitchBloc
|
class WallLightSwitchBloc extends Bloc<WallLightSwitchEvent, WallLightSwitchState> {
|
||||||
extends Bloc<WallLightSwitchEvent, WallLightSwitchState> {
|
late WallLightStatusModel deviceStatus;
|
||||||
WallLightSwitchBloc({required this.deviceId})
|
final String deviceId;
|
||||||
: super(WallLightSwitchInitial()) {
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
|
WallLightSwitchBloc({
|
||||||
|
required this.deviceId,
|
||||||
|
required this.controlDeviceService,
|
||||||
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(WallLightSwitchInitial()) {
|
||||||
on<WallLightSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
on<WallLightSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||||
on<WallLightSwitchControl>(_onControl);
|
on<WallLightSwitchControl>(_onControl);
|
||||||
on<WallLightSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
on<WallLightSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
||||||
@ -20,143 +29,114 @@ class WallLightSwitchBloc
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
late WallLightStatusModel deviceStatus;
|
Future<void> _onFetchDeviceStatus(
|
||||||
final String deviceId;
|
WallLightSwitchFetchDeviceEvent event,
|
||||||
Timer? _timer;
|
Emitter<WallLightSwitchState> emit,
|
||||||
|
) async {
|
||||||
FutureOr<void> _onFetchDeviceStatus(WallLightSwitchFetchDeviceEvent event,
|
|
||||||
Emitter<WallLightSwitchState> emit) async {
|
|
||||||
emit(WallLightSwitchLoading());
|
emit(WallLightSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
_listenToChanges(event.deviceId, emit);
|
||||||
|
deviceStatus = WallLightStatusModel.fromJson(event.deviceId, status.status);
|
||||||
deviceStatus =
|
|
||||||
WallLightStatusModel.fromJson(event.deviceId, status.status);
|
|
||||||
_listenToChanges(event.deviceId);
|
|
||||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WallLightSwitchError(e.toString()));
|
emit(WallLightSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _listenToChanges(
|
||||||
|
String deviceId,
|
||||||
|
Emitter<WallLightSwitchState> emit,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final stream = ref.onValue;
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
stream.listen((DatabaseEvent event) {
|
||||||
Map<dynamic, dynamic> usersMap =
|
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
if (data == null) return;
|
||||||
|
|
||||||
List<Status> statusList = [];
|
final statusList = <Status>[];
|
||||||
usersMap['status'].forEach((element) {
|
if (data['status'] != null) {
|
||||||
statusList
|
for (var element in data['status']) {
|
||||||
.add(Status(code: element['code'], value: element['value']));
|
statusList.add(
|
||||||
});
|
Status(
|
||||||
|
code: element['code'].toString(),
|
||||||
deviceStatus =
|
value: element['value'].toString(),
|
||||||
WallLightStatusModel.fromJson(usersMap['productUuid'], statusList);
|
),
|
||||||
if (!isClosed) {
|
);
|
||||||
add(StatusUpdated(deviceStatus));
|
}
|
||||||
|
}
|
||||||
|
if (statusList.isNotEmpty) {
|
||||||
|
final newStatus = WallLightStatusModel.fromJson(deviceId, statusList);
|
||||||
|
if (newStatus != deviceStatus) {
|
||||||
|
deviceStatus = newStatus;
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (e) {
|
||||||
|
emit(WallLightSwitchError('Failed to listen to changes: $e'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(
|
void _onStatusUpdated(
|
||||||
StatusUpdated event, Emitter<WallLightSwitchState> emit) {
|
StatusUpdated event,
|
||||||
|
Emitter<WallLightSwitchState> emit,
|
||||||
|
) {
|
||||||
|
emit(WallLightSwitchLoading());
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onControl(
|
Future<void> _onControl(
|
||||||
WallLightSwitchControl event, Emitter<WallLightSwitchState> emit) async {
|
WallLightSwitchControl event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<WallLightSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(WallLightSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
|
|
||||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
deviceId: event.deviceId,
|
await controlDeviceService.controlDevice(
|
||||||
code: event.code,
|
deviceUuid: event.deviceId,
|
||||||
value: event.value,
|
status: Status(code: event.code, value: event.value),
|
||||||
oldValue: oldValue,
|
);
|
||||||
emit: emit,
|
} catch (e) {
|
||||||
isBatch: false,
|
_updateLocalValue(event.code, !event.value);
|
||||||
);
|
emit(WallLightSwitchError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
Future<void> _onBatchControl(
|
||||||
required dynamic deviceId,
|
WallLightSwitchBatchControl event,
|
||||||
required String code,
|
Emitter<WallLightSwitchState> emit,
|
||||||
required bool value,
|
) async {
|
||||||
required bool oldValue,
|
emit(WallLightSwitchLoading());
|
||||||
required Emitter<WallLightSwitchState> emit,
|
_updateLocalValue(event.code, event.value);
|
||||||
required bool isBatch,
|
|
||||||
}) async {
|
|
||||||
late String id;
|
|
||||||
|
|
||||||
if (deviceId is List) {
|
|
||||||
id = deviceId.first;
|
|
||||||
} else {
|
|
||||||
id = deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
|
||||||
Emitter<WallLightSwitchState> emit) {
|
|
||||||
_updateLocalValue(code, oldValue);
|
|
||||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||||
}
|
|
||||||
|
|
||||||
void _updateLocalValue(String code, bool value) {
|
try {
|
||||||
if (code == 'switch_1') {
|
await batchControlDevicesService.batchControlDevices(
|
||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
uuids: event.devicesIds,
|
||||||
|
code: event.code,
|
||||||
|
value: event.value,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(WallLightSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _getValueByCode(String code) {
|
Future<void> _onFetchBatchStatus(
|
||||||
switch (code) {
|
WallLightSwitchFetchBatchEvent event,
|
||||||
case 'switch_1':
|
Emitter<WallLightSwitchState> emit,
|
||||||
return deviceStatus.switch1;
|
) async {
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(WallLightSwitchFetchBatchEvent event,
|
|
||||||
Emitter<WallLightSwitchState> emit) async {
|
|
||||||
emit(WallLightSwitchLoading());
|
emit(WallLightSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
WallLightStatusModel.fromJson(event.devicesIds.first, status.status);
|
WallLightStatusModel.fromJson(event.devicesIds.first, status.status);
|
||||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||||
@ -165,32 +145,10 @@ class WallLightSwitchBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
Future<void> _onFactoryReset(
|
||||||
Future<void> close() {
|
WallLightFactoryReset event,
|
||||||
_timer?.cancel();
|
Emitter<WallLightSwitchState> emit,
|
||||||
return super.close();
|
) async {
|
||||||
}
|
|
||||||
|
|
||||||
FutureOr<void> _onBatchControl(WallLightSwitchBatchControl event,
|
|
||||||
Emitter<WallLightSwitchState> emit) async {
|
|
||||||
final oldValue = _getValueByCode(event.code);
|
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value);
|
|
||||||
|
|
||||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
|
||||||
|
|
||||||
await _runDebounce(
|
|
||||||
deviceId: event.devicesIds,
|
|
||||||
code: event.code,
|
|
||||||
value: event.value,
|
|
||||||
oldValue: oldValue,
|
|
||||||
emit: emit,
|
|
||||||
isBatch: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
FutureOr<void> _onFactoryReset(
|
|
||||||
WallLightFactoryReset event, Emitter<WallLightSwitchState> emit) async {
|
|
||||||
emit(WallLightSwitchLoading());
|
emit(WallLightSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
@ -198,12 +156,18 @@ class WallLightSwitchBloc
|
|||||||
event.deviceId,
|
event.deviceId,
|
||||||
);
|
);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(WallLightSwitchError('Failed'));
|
emit(WallLightSwitchError('Failed to reset device'));
|
||||||
} else {
|
} else {
|
||||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
add(WallLightSwitchFetchDeviceEvent(event.deviceId));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WallLightSwitchError(e.toString()));
|
emit(WallLightSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _updateLocalValue(String code, bool value) {
|
||||||
|
if (code == 'switch_1') {
|
||||||
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart';
|
||||||
|
|
||||||
|
abstract final class WallLightSwitchBlocFactory {
|
||||||
|
const WallLightSwitchBlocFactory._();
|
||||||
|
|
||||||
|
static WallLightSwitchBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return WallLightSwitchBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,9 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_re
|
|||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/factories/wall_light_switch_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class WallLightBatchControlView extends StatelessWidget with HelperResponsiveLay
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => WallLightSwitchBloc(deviceId: deviceIds.first)
|
create: (context) => WallLightSwitchBlocFactory.create(deviceId: deviceIds.first)
|
||||||
..add(WallLightSwitchFetchBatchEvent(deviceIds)),
|
..add(WallLightSwitchFetchBatchEvent(deviceIds)),
|
||||||
child: BlocBuilder<WallLightSwitchBloc, WallLightSwitchState>(
|
child: BlocBuilder<WallLightSwitchBloc, WallLightSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/factories/wall_light_switch_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
@ -15,7 +16,7 @@ class WallLightDeviceControl extends StatelessWidget
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => WallLightSwitchBloc(deviceId: deviceId)
|
create: (context) => WallLightSwitchBlocFactory.create(deviceId: deviceId)
|
||||||
..add(WallLightSwitchFetchDeviceEvent(deviceId)),
|
..add(WallLightSwitchFetchDeviceEvent(deviceId)),
|
||||||
child: BlocBuilder<WallLightSwitchBloc, WallLightSwitchState>(
|
child: BlocBuilder<WallLightSwitchBloc, WallLightSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -157,7 +157,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text(
|
SelectableText(
|
||||||
value,
|
value,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.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/three_g_glass_switch/models/three_gang_glass_switch.dart';
|
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/models/three_gang_glass_switch.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
part 'three_gang_glass_switch_event.dart';
|
part 'three_gang_glass_switch_event.dart';
|
||||||
@ -13,19 +16,16 @@ part 'three_gang_glass_switch_state.dart';
|
|||||||
|
|
||||||
class ThreeGangGlassSwitchBloc
|
class ThreeGangGlassSwitchBloc
|
||||||
extends Bloc<ThreeGangGlassSwitchEvent, ThreeGangGlassSwitchState> {
|
extends Bloc<ThreeGangGlassSwitchEvent, ThreeGangGlassSwitchState> {
|
||||||
ThreeGangGlassStatusModel deviceStatus;
|
late ThreeGangGlassStatusModel deviceStatus;
|
||||||
Timer? _timer;
|
final String deviceId;
|
||||||
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
ThreeGangGlassSwitchBloc({required String deviceId})
|
ThreeGangGlassSwitchBloc({
|
||||||
: deviceStatus = ThreeGangGlassStatusModel(
|
required this.deviceId,
|
||||||
uuid: deviceId,
|
required this.controlDeviceService,
|
||||||
switch1: false,
|
required this.batchControlDevicesService,
|
||||||
countDown1: 0,
|
}) : super(ThreeGangGlassSwitchInitial()) {
|
||||||
switch2: false,
|
|
||||||
countDown2: 0,
|
|
||||||
switch3: false,
|
|
||||||
countDown3: 0),
|
|
||||||
super(ThreeGangGlassSwitchInitial()) {
|
|
||||||
on<ThreeGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
on<ThreeGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||||
on<ThreeGangGlassSwitchControl>(_onControl);
|
on<ThreeGangGlassSwitchControl>(_onControl);
|
||||||
on<ThreeGangGlassSwitchBatchControl>(_onBatchControl);
|
on<ThreeGangGlassSwitchBatchControl>(_onBatchControl);
|
||||||
@ -34,188 +34,154 @@ class ThreeGangGlassSwitchBloc
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDeviceStatus(ThreeGangGlassSwitchFetchDeviceEvent event,
|
Future<void> _onFetchDeviceStatus(
|
||||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
ThreeGangGlassSwitchFetchDeviceEvent event,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
emit(ThreeGangGlassSwitchLoading());
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
_listenToChanges(event.deviceId, emit);
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
_listenToChanges(event.deviceId);
|
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ThreeGangGlassSwitchError(e.toString()));
|
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _listenToChanges(
|
||||||
|
String deviceId,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final stream = ref.onValue;
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
stream.listen((DatabaseEvent event) {
|
||||||
Map<dynamic, dynamic> usersMap =
|
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
if (data == null) return;
|
||||||
|
|
||||||
List<Status> statusList = [];
|
final statusList = <Status>[];
|
||||||
usersMap['status'].forEach((element) {
|
if (data['status'] != null) {
|
||||||
statusList
|
for (var element in data['status']) {
|
||||||
.add(Status(code: element['code'], value: element['value']));
|
statusList.add(
|
||||||
});
|
Status(
|
||||||
|
code: element['code'].toString(),
|
||||||
deviceStatus = ThreeGangGlassStatusModel.fromJson(
|
value: element['value'].toString(),
|
||||||
usersMap['productUuid'], statusList);
|
),
|
||||||
if (!isClosed) {
|
);
|
||||||
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(
|
||||||
StatusUpdated event, Emitter<ThreeGangGlassSwitchState> emit) {
|
StatusUpdated event,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit,
|
||||||
|
) {
|
||||||
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onControl(ThreeGangGlassSwitchControl event,
|
Future<void> _onControl(
|
||||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
ThreeGangGlassSwitchControl event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<ThreeGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
deviceId: event.deviceId,
|
await controlDeviceService.controlDevice(
|
||||||
code: event.code,
|
deviceUuid: event.deviceId,
|
||||||
value: event.value,
|
status: Status(code: event.code, value: event.value),
|
||||||
oldValue: oldValue,
|
);
|
||||||
emit: emit,
|
} catch (e) {
|
||||||
isBatch: false,
|
_updateLocalValue(event.code, !event.value);
|
||||||
);
|
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(ThreeGangGlassSwitchBatchControl event,
|
Future<void> _onBatchControl(
|
||||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
ThreeGangGlassSwitchBatchControl event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<ThreeGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
deviceId: event.deviceIds,
|
await batchControlDevicesService.batchControlDevices(
|
||||||
code: event.code,
|
uuids: event.deviceIds,
|
||||||
value: event.value,
|
code: event.code,
|
||||||
oldValue: oldValue,
|
value: event.value,
|
||||||
emit: emit,
|
);
|
||||||
isBatch: true,
|
} catch (e) {
|
||||||
);
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(
|
Future<void> _onFetchBatchStatus(
|
||||||
ThreeGangGlassSwitchFetchBatchStatusEvent event,
|
ThreeGangGlassSwitchFetchBatchStatusEvent event,
|
||||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
Emitter<ThreeGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
emit(ThreeGangGlassSwitchLoading());
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
deviceStatus =
|
||||||
deviceStatus = ThreeGangGlassStatusModel.fromJson(
|
ThreeGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
|
||||||
event.deviceIds.first, status.status);
|
|
||||||
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ThreeGangGlassSwitchError(e.toString()));
|
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFactoryReset(ThreeGangGlassFactoryReset event,
|
Future<void> _onFactoryReset(
|
||||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
ThreeGangGlassFactoryReset event,
|
||||||
|
Emitter<ThreeGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
emit(ThreeGangGlassSwitchLoading());
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi()
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
.factoryReset(event.factoryReset, event.deviceId);
|
event.factoryReset,
|
||||||
|
event.deviceId,
|
||||||
|
);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(ThreeGangGlassSwitchError('Failed'));
|
emit(ThreeGangGlassSwitchError('Failed to reset device'));
|
||||||
} else {
|
} else {
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
add(ThreeGangGlassSwitchFetchDeviceEvent(event.deviceId));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ThreeGangGlassSwitchError(e.toString()));
|
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
|
||||||
required dynamic deviceId,
|
|
||||||
required String code,
|
|
||||||
required bool value,
|
|
||||||
required bool oldValue,
|
|
||||||
required Emitter<ThreeGangGlassSwitchState> emit,
|
|
||||||
required bool isBatch,
|
|
||||||
}) async {
|
|
||||||
late String id;
|
|
||||||
if (deviceId is List) {
|
|
||||||
id = deviceId.first;
|
|
||||||
} else {
|
|
||||||
id = deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
|
||||||
Emitter<ThreeGangGlassSwitchState> emit) {
|
|
||||||
_updateLocalValue(code, oldValue);
|
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateLocalValue(String code, bool value) {
|
void _updateLocalValue(String code, bool value) {
|
||||||
if (code == 'switch_1') {
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
|
||||||
} else if (code == 'switch_2') {
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch2: value);
|
|
||||||
} else if (code == 'switch_3') {
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch3: value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _getValueByCode(String code) {
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 'switch_1':
|
case 'switch_1':
|
||||||
return deviceStatus.switch1;
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
|
break;
|
||||||
case 'switch_2':
|
case 'switch_2':
|
||||||
return deviceStatus.switch2;
|
deviceStatus = deviceStatus.copyWith(switch2: value);
|
||||||
|
break;
|
||||||
case 'switch_3':
|
case 'switch_3':
|
||||||
return deviceStatus.switch3;
|
deviceStatus = deviceStatus.copyWith(switch3: value);
|
||||||
default:
|
break;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() {
|
|
||||||
_timer?.cancel();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
part of 'three_gang_glass_switch_bloc.dart';
|
part of 'three_gang_glass_switch_bloc.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
abstract class ThreeGangGlassSwitchEvent {}
|
abstract class ThreeGangGlassSwitchEvent extends Equatable {
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
class ThreeGangGlassSwitchFetchDeviceEvent extends ThreeGangGlassSwitchEvent {
|
class ThreeGangGlassSwitchFetchDeviceEvent extends ThreeGangGlassSwitchEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
@ -19,6 +22,9 @@ class ThreeGangGlassSwitchControl extends ThreeGangGlassSwitchEvent {
|
|||||||
required this.code,
|
required this.code,
|
||||||
required this.value,
|
required this.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [deviceId, code, value];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangGlassSwitchBatchControl extends ThreeGangGlassSwitchEvent {
|
class ThreeGangGlassSwitchBatchControl extends ThreeGangGlassSwitchEvent {
|
||||||
@ -31,6 +37,9 @@ class ThreeGangGlassSwitchBatchControl extends ThreeGangGlassSwitchEvent {
|
|||||||
required this.code,
|
required this.code,
|
||||||
required this.value,
|
required this.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [deviceIds, code, value];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangGlassSwitchFetchBatchStatusEvent
|
class ThreeGangGlassSwitchFetchBatchStatusEvent
|
||||||
@ -38,6 +47,9 @@ class ThreeGangGlassSwitchFetchBatchStatusEvent
|
|||||||
final List<String> deviceIds;
|
final List<String> deviceIds;
|
||||||
|
|
||||||
ThreeGangGlassSwitchFetchBatchStatusEvent(this.deviceIds);
|
ThreeGangGlassSwitchFetchBatchStatusEvent(this.deviceIds);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [deviceIds];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent {
|
class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent {
|
||||||
@ -48,6 +60,9 @@ class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent {
|
|||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
required this.factoryReset,
|
required this.factoryReset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [deviceId, factoryReset];
|
||||||
}
|
}
|
||||||
|
|
||||||
class StatusUpdated extends ThreeGangGlassSwitchEvent {
|
class StatusUpdated extends ThreeGangGlassSwitchEvent {
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart';
|
||||||
|
|
||||||
|
abstract final class ThreeGangGlassSwitchBlocFactory {
|
||||||
|
const ThreeGangGlassSwitchBlocFactory._();
|
||||||
|
|
||||||
|
static ThreeGangGlassSwitchBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return ThreeGangGlassSwitchBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_
|
|||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/factories/three_gang_glass_switch_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/models/three_gang_glass_switch.dart';
|
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/models/three_gang_glass_switch.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ class ThreeGangGlassSwitchBatchControlView extends StatelessWidget with HelperRe
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => ThreeGangGlassSwitchBloc(deviceId: deviceIds.first)
|
create: (context) => ThreeGangGlassSwitchBlocFactory.create(deviceId: deviceIds.first)
|
||||||
..add(ThreeGangGlassSwitchFetchBatchStatusEvent(deviceIds)),
|
..add(ThreeGangGlassSwitchFetchBatchStatusEvent(deviceIds)),
|
||||||
child: BlocBuilder<ThreeGangGlassSwitchBloc, ThreeGangGlassSwitchState>(
|
child: BlocBuilder<ThreeGangGlassSwitchBloc, ThreeGangGlassSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/factories/three_gang_glass_switch_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget with HelperRespons
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
ThreeGangGlassSwitchBloc(deviceId: deviceId)..add(ThreeGangGlassSwitchFetchDeviceEvent(deviceId)),
|
ThreeGangGlassSwitchBlocFactory.create(deviceId: deviceId)..add(ThreeGangGlassSwitchFetchDeviceEvent(deviceId)),
|
||||||
child: BlocBuilder<ThreeGangGlassSwitchBloc, ThreeGangGlassSwitchState>(
|
child: BlocBuilder<ThreeGangGlassSwitchBloc, ThreeGangGlassSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is ThreeGangGlassSwitchLoading) {
|
if (state is ThreeGangGlassSwitchLoading) {
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:bloc/bloc.dart';
|
import 'dart:developer';
|
||||||
|
|
||||||
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_bloc/flutter_bloc.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/three_gang_switch/models/living_room_model.dart';
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
part 'living_room_event.dart';
|
part 'living_room_event.dart';
|
||||||
@ -15,9 +17,14 @@ part 'living_room_state.dart';
|
|||||||
class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
||||||
late LivingRoomStatusModel deviceStatus;
|
late LivingRoomStatusModel deviceStatus;
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
Timer? _timer;
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
LivingRoomBloc({required this.deviceId}) : super(LivingRoomInitial()) {
|
LivingRoomBloc({
|
||||||
|
required this.deviceId,
|
||||||
|
required this.controlDeviceService,
|
||||||
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(LivingRoomInitial()) {
|
||||||
on<LivingRoomFetchDeviceStatusEvent>(_onFetchDeviceStatus);
|
on<LivingRoomFetchDeviceStatusEvent>(_onFetchDeviceStatus);
|
||||||
on<LivingRoomControl>(_livingRoomControl);
|
on<LivingRoomControl>(_livingRoomControl);
|
||||||
on<LivingRoomBatchControl>(_livingRoomBatchControl);
|
on<LivingRoomBatchControl>(_livingRoomBatchControl);
|
||||||
@ -26,156 +33,108 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchDeviceStatus(LivingRoomFetchDeviceStatusEvent event,
|
Future<void> _onFetchDeviceStatus(
|
||||||
Emitter<LivingRoomState> emit) async {
|
LivingRoomFetchDeviceStatusEvent event,
|
||||||
|
Emitter<LivingRoomState> emit,
|
||||||
|
) async {
|
||||||
emit(LivingRoomDeviceStatusLoading());
|
emit(LivingRoomDeviceStatusLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
|
||||||
deviceStatus =
|
|
||||||
LivingRoomStatusModel.fromJson(event.deviceId, status.status);
|
|
||||||
_listenToChanges(deviceId);
|
_listenToChanges(deviceId);
|
||||||
|
deviceStatus = LivingRoomStatusModel.fromJson(event.deviceId, status.status);
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _livingRoomControl(
|
void _listenToChanges(String deviceId) {
|
||||||
LivingRoomControl event, Emitter<LivingRoomState> emit) async {
|
try {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
|
ref.onValue.listen((event) {
|
||||||
|
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
eventsMap['status'].forEach((element) {
|
||||||
|
statusList.add(
|
||||||
|
Status(code: element['code'], value: element['value']),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus = LivingRoomStatusModel.fromJson(deviceId, statusList);
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
});
|
||||||
|
} catch (_) {
|
||||||
|
log('Error listening to changes');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event,
|
||||||
|
Emitter<LivingRoomState> emit,
|
||||||
|
) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _livingRoomControl(
|
||||||
|
LivingRoomControl event,
|
||||||
|
Emitter<LivingRoomState> emit,
|
||||||
|
) async {
|
||||||
|
emit(LivingRoomDeviceStatusLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
|
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
deviceId: event.deviceId,
|
await controlDeviceService.controlDevice(
|
||||||
code: event.code,
|
deviceUuid: event.deviceId,
|
||||||
value: event.value,
|
status: Status(code: event.code, value: event.value),
|
||||||
oldValue: oldValue,
|
);
|
||||||
emit: emit,
|
} catch (e) {
|
||||||
isBatch: false,
|
_updateLocalValue(event.code, !event.value);
|
||||||
);
|
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
Future<void> _livingRoomBatchControl(
|
||||||
required dynamic deviceId,
|
LivingRoomBatchControl event,
|
||||||
required String code,
|
Emitter<LivingRoomState> emit,
|
||||||
required dynamic value,
|
) async {
|
||||||
required dynamic oldValue,
|
emit(LivingRoomDeviceStatusLoading());
|
||||||
required Emitter<LivingRoomState> emit,
|
_updateLocalValue(event.code, event.value);
|
||||||
required bool isBatch,
|
|
||||||
}) async {
|
|
||||||
late String id;
|
|
||||||
|
|
||||||
if (deviceId is List) {
|
|
||||||
id = deviceId.first;
|
|
||||||
} else {
|
|
||||||
id = deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
_timer = Timer(const Duration(seconds: 1), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValueAndEmit(String deviceId, String code, dynamic oldValue,
|
|
||||||
Emitter<LivingRoomState> emit) {
|
|
||||||
_updateLocalValue(code, oldValue);
|
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||||
}
|
|
||||||
|
|
||||||
void _updateLocalValue(String code, dynamic value) {
|
try {
|
||||||
switch (code) {
|
await batchControlDevicesService.batchControlDevices(
|
||||||
case 'switch_1':
|
uuids: event.devicesIds,
|
||||||
if (value is bool) {
|
code: event.code,
|
||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
value: event.value,
|
||||||
}
|
);
|
||||||
break;
|
} catch (e) {
|
||||||
case 'switch_2':
|
_updateLocalValue(event.code, !event.value);
|
||||||
if (value is bool) {
|
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||||
deviceStatus = deviceStatus.copyWith(switch2: value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'switch_3':
|
|
||||||
if (value is bool) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch3: value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _getValueByCode(String code) {
|
|
||||||
switch (code) {
|
|
||||||
case 'switch_1':
|
|
||||||
return deviceStatus.switch1;
|
|
||||||
case 'switch_2':
|
|
||||||
return deviceStatus.switch2;
|
|
||||||
case 'switch_3':
|
|
||||||
return deviceStatus.switch3;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _livingRoomFetchBatchControl(
|
Future<void> _livingRoomFetchBatchControl(
|
||||||
LivingRoomFetchBatchEvent event, Emitter<LivingRoomState> emit) async {
|
LivingRoomFetchBatchEvent event,
|
||||||
|
Emitter<LivingRoomState> emit,
|
||||||
|
) async {
|
||||||
emit(LivingRoomDeviceStatusLoading());
|
emit(LivingRoomDeviceStatusLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
LivingRoomStatusModel.fromJson(event.devicesIds.first, status.status);
|
LivingRoomStatusModel.fromJson(event.devicesIds.first, status.status);
|
||||||
// for (var deviceId in event.devicesIds) {
|
|
||||||
// _listenToChanges(deviceId);
|
|
||||||
// }
|
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _livingRoomBatchControl(
|
Future<void> _livingRoomFactoryReset(
|
||||||
LivingRoomBatchControl event, Emitter<LivingRoomState> emit) async {
|
LivingRoomFactoryResetEvent event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<LivingRoomState> emit,
|
||||||
|
) async {
|
||||||
_updateLocalValue(event.code, event.value);
|
|
||||||
|
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
|
||||||
|
|
||||||
await _runDebounce(
|
|
||||||
deviceId: event.devicesIds,
|
|
||||||
code: event.code,
|
|
||||||
value: event.value,
|
|
||||||
oldValue: oldValue,
|
|
||||||
emit: emit,
|
|
||||||
isBatch: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
FutureOr<void> _livingRoomFactoryReset(
|
|
||||||
LivingRoomFactoryResetEvent event, Emitter<LivingRoomState> emit) async {
|
|
||||||
emit(LivingRoomDeviceStatusLoading());
|
emit(LivingRoomDeviceStatusLoading());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
@ -183,42 +142,28 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
|||||||
event.uuid,
|
event.uuid,
|
||||||
);
|
);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(const LivingRoomDeviceManagementError('Failed'));
|
emit(const LivingRoomDeviceManagementError('Failed to reset device'));
|
||||||
} else {
|
} else {
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
add(LivingRoomFetchDeviceStatusEvent(event.uuid));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _updateLocalValue(String code, dynamic value) {
|
||||||
try {
|
if (value is! bool) return;
|
||||||
DatabaseReference ref =
|
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
switch (code) {
|
||||||
Map<dynamic, dynamic> usersMap =
|
case 'switch_1':
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
|
break;
|
||||||
List<Status> statusList = [];
|
case 'switch_2':
|
||||||
usersMap['status'].forEach((element) {
|
deviceStatus = deviceStatus.copyWith(switch2: value);
|
||||||
statusList
|
break;
|
||||||
.add(Status(code: element['code'], value: element['value']));
|
case 'switch_3':
|
||||||
});
|
deviceStatus = deviceStatus.copyWith(switch3: value);
|
||||||
|
break;
|
||||||
deviceStatus =
|
}
|
||||||
LivingRoomStatusModel.fromJson(usersMap['productUuid'], statusList);
|
|
||||||
if (!isClosed) {
|
|
||||||
add(StatusUpdated(deviceStatus));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onStatusUpdated(StatusUpdated event, Emitter<LivingRoomState> emit) {
|
|
||||||
deviceStatus = event.deviceStatus;
|
|
||||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart';
|
||||||
|
|
||||||
|
abstract final class LivingRoomBlocFactory {
|
||||||
|
const LivingRoomBlocFactory._();
|
||||||
|
|
||||||
|
static LivingRoomBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return LivingRoomBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_re
|
|||||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/factories/living_room_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart';
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
@ -17,7 +18,7 @@ class LivingRoomBatchControlsView extends StatelessWidget with HelperResponsiveL
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
LivingRoomBloc(deviceId: deviceIds.first)..add(LivingRoomFetchBatchEvent(deviceIds)),
|
LivingRoomBlocFactory.create(deviceId: deviceIds.first)..add(LivingRoomFetchBatchEvent(deviceIds)),
|
||||||
child: BlocBuilder<LivingRoomBloc, LivingRoomState>(
|
child: BlocBuilder<LivingRoomBloc, LivingRoomState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is LivingRoomDeviceStatusLoading) {
|
if (state is LivingRoomDeviceStatusLoading) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/factories/living_room_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart';
|
import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
@ -14,7 +15,7 @@ class LivingRoomDeviceControlsView extends StatelessWidget
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => LivingRoomBloc(deviceId: deviceId)
|
create: (context) => LivingRoomBlocFactory.create(deviceId: deviceId)
|
||||||
..add(LivingRoomFetchDeviceStatusEvent(deviceId)),
|
..add(LivingRoomFetchDeviceStatusEvent(deviceId)),
|
||||||
child: BlocBuilder<LivingRoomBloc, LivingRoomState>(
|
child: BlocBuilder<LivingRoomBloc, LivingRoomState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -1,26 +1,33 @@
|
|||||||
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:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:meta/meta.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/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> {
|
||||||
TwoGangGlassStatusModel deviceStatus;
|
final String deviceId;
|
||||||
Timer? _timer;
|
final ControlDeviceService controlDeviceService;
|
||||||
TwoGangGlassSwitchBloc({required String deviceId})
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
: deviceStatus = TwoGangGlassStatusModel(
|
|
||||||
uuid: deviceId,
|
late TwoGangGlassStatusModel deviceStatus;
|
||||||
switch1: false,
|
|
||||||
countDown1: 0,
|
TwoGangGlassSwitchBloc({
|
||||||
switch2: false,
|
required this.deviceId,
|
||||||
countDown2: 0),
|
required this.controlDeviceService,
|
||||||
super(TwoGangGlassSwitchInitial()) {
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(TwoGangGlassSwitchInitial()) {
|
||||||
on<TwoGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
on<TwoGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||||
on<TwoGangGlassSwitchControl>(_onControl);
|
on<TwoGangGlassSwitchControl>(_onControl);
|
||||||
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
||||||
@ -29,14 +36,14 @@ class TwoGangGlassSwitchBloc
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDeviceStatus(TwoGangGlassSwitchFetchDeviceEvent event,
|
Future<void> _onFetchDeviceStatus(
|
||||||
Emitter<TwoGangGlassSwitchState> emit) async {
|
TwoGangGlassSwitchFetchDeviceEvent event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
emit(TwoGangGlassSwitchLoading());
|
emit(TwoGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
deviceStatus = TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
deviceStatus =
|
|
||||||
TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
|
||||||
_listenToChanges(event.deviceId);
|
_listenToChanges(event.deviceId);
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -46,200 +53,121 @@ class TwoGangGlassSwitchBloc
|
|||||||
|
|
||||||
void _listenToChanges(String deviceId) {
|
void _listenToChanges(String deviceId) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
final ref = FirebaseDatabase.instance.ref(
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
'device-status/$deviceId',
|
||||||
ref.onValue.listen((DatabaseEvent event) {
|
);
|
||||||
if (event.snapshot.value == null) return;
|
|
||||||
|
ref.onValue.listen((event) {
|
||||||
|
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
|
||||||
Map<dynamic, dynamic> data =
|
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
|
||||||
List<Status> statusList = [];
|
List<Status> statusList = [];
|
||||||
|
eventsMap['status'].forEach((element) {
|
||||||
data['status'].forEach((element) {
|
statusList.add(Status(code: element['code'], value: element['value']));
|
||||||
statusList
|
|
||||||
.add(Status(code: element['code'], value: element['value']));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Parse the new status and add the event
|
deviceStatus = TwoGangGlassStatusModel.fromJson(deviceId, statusList);
|
||||||
final updatedStatus =
|
add(StatusUpdated(deviceStatus));
|
||||||
TwoGangGlassStatusModel.fromJson(data['productUuid'], statusList);
|
|
||||||
if (!isClosed) {
|
|
||||||
add(StatusUpdated(updatedStatus));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
// Handle errors and emit an error state if necessary
|
log(
|
||||||
if (!isClosed) {
|
'Error listening to changes',
|
||||||
// add(TwoGangGlassSwitchError('Error listening to updates: $e'));
|
name: 'TwoGangGlassSwitchBloc._listenToChanges',
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onControl(TwoGangGlassSwitchControl event,
|
Future<void> _onControl(
|
||||||
Emitter<TwoGangGlassSwitchState> emit) async {
|
TwoGangGlassSwitchControl event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangGlassSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
deviceId: event.deviceId,
|
await controlDeviceService.controlDevice(
|
||||||
code: event.code,
|
deviceUuid: event.deviceId,
|
||||||
value: event.value,
|
status: Status(code: event.code, value: event.value),
|
||||||
oldValue: oldValue,
|
);
|
||||||
emit: emit,
|
} catch (e) {
|
||||||
isBatch: false,
|
_updateLocalValue(event.code, !event.value);
|
||||||
);
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(TwoGangGlassSwitchBatchControl event,
|
Future<void> _onBatchControl(
|
||||||
Emitter<TwoGangGlassSwitchState> emit) async {
|
TwoGangGlassSwitchBatchControl event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangGlassSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
deviceId: event.deviceIds,
|
await batchControlDevicesService.batchControlDevices(
|
||||||
code: event.code,
|
uuids: event.deviceIds,
|
||||||
value: event.value,
|
code: event.code,
|
||||||
oldValue: oldValue,
|
value: event.value,
|
||||||
emit: emit,
|
);
|
||||||
isBatch: true,
|
} catch (e) {
|
||||||
);
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(
|
Future<void> _onFetchBatchStatus(
|
||||||
TwoGangGlassSwitchFetchBatchStatusEvent event,
|
TwoGangGlassSwitchFetchBatchStatusEvent event,
|
||||||
Emitter<TwoGangGlassSwitchState> emit) async {
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
emit(TwoGangGlassSwitchLoading());
|
emit(TwoGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
|
||||||
deviceStatus = TwoGangGlassStatusModel.fromJson(
|
deviceStatus = TwoGangGlassStatusModel.fromJson(
|
||||||
event.deviceIds.first, status.status);
|
event.deviceIds.first,
|
||||||
|
status.status,
|
||||||
|
);
|
||||||
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFactoryReset(TwoGangGlassFactoryReset event,
|
Future<void> _onFactoryReset(
|
||||||
Emitter<TwoGangGlassSwitchState> emit) async {
|
TwoGangGlassFactoryReset event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
emit(TwoGangGlassSwitchLoading());
|
emit(TwoGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi()
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
.factoryReset(event.factoryReset, event.deviceId);
|
event.factoryReset,
|
||||||
|
event.deviceId,
|
||||||
|
);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(TwoGangGlassSwitchError('Failed'));
|
emit(TwoGangGlassSwitchError('Failed to reset device'));
|
||||||
} else {
|
} else {
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
add(TwoGangGlassSwitchFetchDeviceEvent(event.deviceId));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
void _onStatusUpdated(
|
||||||
required dynamic deviceId,
|
StatusUpdated event,
|
||||||
required String code,
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
required bool value,
|
) {
|
||||||
required bool oldValue,
|
deviceStatus = event.deviceStatus;
|
||||||
required Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
required bool isBatch,
|
|
||||||
}) async {
|
|
||||||
late String id;
|
|
||||||
if (deviceId is List) {
|
|
||||||
id = deviceId.first;
|
|
||||||
} else {
|
|
||||||
id = deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit) {
|
|
||||||
_updateLocalValue(code, oldValue);
|
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateLocalValue(String code, bool value) {
|
void _updateLocalValue(String code, bool value) {
|
||||||
if (code == 'switch_1') {
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
|
||||||
} else if (code == 'switch_2') {
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch2: value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _getValueByCode(String code) {
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 'switch_1':
|
case 'switch_1':
|
||||||
return deviceStatus.switch1;
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
|
break;
|
||||||
case 'switch_2':
|
case 'switch_2':
|
||||||
return deviceStatus.switch2;
|
deviceStatus = deviceStatus.copyWith(switch2: value);
|
||||||
default:
|
break;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() {
|
|
||||||
_timer?.cancel();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// _listenToChanges(deviceId) {
|
|
||||||
// try {
|
|
||||||
// DatabaseReference ref =
|
|
||||||
// FirebaseDatabase.instance.ref('device-status/$deviceId');
|
|
||||||
// Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
// stream.listen((DatabaseEvent event) {
|
|
||||||
// Map<dynamic, dynamic> usersMap =
|
|
||||||
// event.snapshot.value as Map<dynamic, dynamic>;
|
|
||||||
|
|
||||||
// List<Status> statusList = [];
|
|
||||||
// usersMap['status'].forEach((element) {
|
|
||||||
// statusList
|
|
||||||
// .add(Status(code: element['code'], value: element['value']));
|
|
||||||
// });
|
|
||||||
|
|
||||||
// deviceStatus = TwoGangGlassStatusModel.fromJson(
|
|
||||||
// usersMap['productUuid'], statusList);
|
|
||||||
// if (!isClosed) {
|
|
||||||
// add(StatusUpdated(deviceStatus));
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// } catch (_) {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
void _onStatusUpdated(
|
|
||||||
StatusUpdated event, Emitter<TwoGangGlassSwitchState> emit) {
|
|
||||||
// Update the local deviceStatus with the new status from the event
|
|
||||||
deviceStatus = event.deviceStatus;
|
|
||||||
// Emit the new state with the updated status
|
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
part of 'two_gang_glass_switch_bloc.dart';
|
part of 'two_gang_glass_switch_bloc.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
abstract class TwoGangGlassSwitchEvent {}
|
abstract class TwoGangGlassSwitchEvent extends Equatable {
|
||||||
|
const TwoGangGlassSwitchEvent();
|
||||||
|
}
|
||||||
|
|
||||||
class TwoGangGlassSwitchFetchDeviceEvent extends TwoGangGlassSwitchEvent {
|
class TwoGangGlassSwitchFetchDeviceEvent extends TwoGangGlassSwitchEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
|
||||||
TwoGangGlassSwitchFetchDeviceEvent(this.deviceId);
|
const TwoGangGlassSwitchFetchDeviceEvent(this.deviceId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
class TwoGangGlassSwitchControl extends TwoGangGlassSwitchEvent {
|
class TwoGangGlassSwitchControl extends TwoGangGlassSwitchEvent {
|
||||||
@ -14,11 +19,14 @@ class TwoGangGlassSwitchControl extends TwoGangGlassSwitchEvent {
|
|||||||
final String code;
|
final String code;
|
||||||
final bool value;
|
final bool value;
|
||||||
|
|
||||||
TwoGangGlassSwitchControl({
|
const TwoGangGlassSwitchControl({
|
||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
required this.code,
|
required this.code,
|
||||||
required this.value,
|
required this.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceId, code, value];
|
||||||
}
|
}
|
||||||
|
|
||||||
class TwoGangGlassSwitchBatchControl extends TwoGangGlassSwitchEvent {
|
class TwoGangGlassSwitchBatchControl extends TwoGangGlassSwitchEvent {
|
||||||
@ -26,33 +34,43 @@ class TwoGangGlassSwitchBatchControl extends TwoGangGlassSwitchEvent {
|
|||||||
final String code;
|
final String code;
|
||||||
final bool value;
|
final bool value;
|
||||||
|
|
||||||
TwoGangGlassSwitchBatchControl({
|
const TwoGangGlassSwitchBatchControl({
|
||||||
required this.deviceIds,
|
required this.deviceIds,
|
||||||
required this.code,
|
required this.code,
|
||||||
required this.value,
|
required this.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceIds, code, value];
|
||||||
}
|
}
|
||||||
|
|
||||||
class TwoGangGlassSwitchFetchBatchStatusEvent extends TwoGangGlassSwitchEvent {
|
class TwoGangGlassSwitchFetchBatchStatusEvent extends TwoGangGlassSwitchEvent {
|
||||||
final List<String> deviceIds;
|
final List<String> deviceIds;
|
||||||
|
|
||||||
TwoGangGlassSwitchFetchBatchStatusEvent(this.deviceIds);
|
const TwoGangGlassSwitchFetchBatchStatusEvent(this.deviceIds);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceIds];
|
||||||
}
|
}
|
||||||
|
|
||||||
class TwoGangGlassFactoryReset extends TwoGangGlassSwitchEvent {
|
class TwoGangGlassFactoryReset extends TwoGangGlassSwitchEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
final FactoryResetModel factoryReset;
|
final FactoryResetModel factoryReset;
|
||||||
|
|
||||||
TwoGangGlassFactoryReset({
|
const TwoGangGlassFactoryReset({
|
||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
required this.factoryReset,
|
required this.factoryReset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [deviceId, factoryReset];
|
||||||
}
|
}
|
||||||
|
|
||||||
class StatusUpdated extends TwoGangGlassSwitchEvent {
|
class StatusUpdated extends TwoGangGlassSwitchEvent {
|
||||||
final TwoGangGlassStatusModel deviceStatus;
|
final TwoGangGlassStatusModel deviceStatus;
|
||||||
StatusUpdated(this.deviceStatus);
|
|
||||||
|
const StatusUpdated(this.deviceStatus);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceStatus];
|
List<Object> get props => [deviceStatus];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart';
|
||||||
|
|
||||||
|
abstract final class TwoGangGlassSwitchBlocFactory {
|
||||||
|
const TwoGangGlassSwitchBlocFactory._();
|
||||||
|
|
||||||
|
static TwoGangGlassSwitchBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return TwoGangGlassSwitchBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_
|
|||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/factories/two_gang_glass_switch_bloc_factory.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/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ class TwoGangGlassSwitchBatchControlView extends StatelessWidget with HelperResp
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => TwoGangGlassSwitchBloc(deviceId: deviceIds.first)
|
create: (context) => TwoGangGlassSwitchBlocFactory.create(deviceId: deviceIds.first)
|
||||||
..add(TwoGangGlassSwitchFetchBatchStatusEvent(deviceIds)),
|
..add(TwoGangGlassSwitchFetchBatchStatusEvent(deviceIds)),
|
||||||
child: BlocBuilder<TwoGangGlassSwitchBloc, TwoGangGlassSwitchState>(
|
child: BlocBuilder<TwoGangGlassSwitchBloc, TwoGangGlassSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/factories/two_gang_glass_switch_bloc_factory.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/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
@ -15,7 +16,7 @@ class TwoGangGlassSwitchControlView extends StatelessWidget
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => TwoGangGlassSwitchBloc(deviceId: deviceId)
|
create: (context) => TwoGangGlassSwitchBlocFactory.create(deviceId: deviceId)
|
||||||
..add(TwoGangGlassSwitchFetchDeviceEvent(deviceId)),
|
..add(TwoGangGlassSwitchFetchDeviceEvent(deviceId)),
|
||||||
child: BlocBuilder<TwoGangGlassSwitchBloc, TwoGangGlassSwitchState>(
|
child: BlocBuilder<TwoGangGlassSwitchBloc, TwoGangGlassSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
@ -6,10 +7,22 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_sta
|
|||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_state.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_state.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/models/two_gang_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/models/two_gang_status_model.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
||||||
TwoGangSwitchBloc({required this.deviceId}) : super(TwoGangSwitchInitial()) {
|
final String deviceId;
|
||||||
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
|
late TwoGangStatusModel deviceStatus;
|
||||||
|
|
||||||
|
TwoGangSwitchBloc({
|
||||||
|
required this.deviceId,
|
||||||
|
required this.controlDeviceService,
|
||||||
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(TwoGangSwitchInitial()) {
|
||||||
on<TwoGangSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
on<TwoGangSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||||
on<TwoGangSwitchControl>(_onControl);
|
on<TwoGangSwitchControl>(_onControl);
|
||||||
on<TwoGangSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
on<TwoGangSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
||||||
@ -18,16 +31,13 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
late TwoGangStatusModel deviceStatus;
|
Future<void> _onFetchDeviceStatus(
|
||||||
final String deviceId;
|
TwoGangSwitchFetchDeviceEvent event,
|
||||||
Timer? _timer;
|
Emitter<TwoGangSwitchState> emit,
|
||||||
|
) async {
|
||||||
FutureOr<void> _onFetchDeviceStatus(TwoGangSwitchFetchDeviceEvent event,
|
|
||||||
Emitter<TwoGangSwitchState> emit) async {
|
|
||||||
emit(TwoGangSwitchLoading());
|
emit(TwoGangSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
|
||||||
deviceStatus = TwoGangStatusModel.fromJson(event.deviceId, status.status);
|
deviceStatus = TwoGangStatusModel.fromJson(event.deviceId, status.status);
|
||||||
_listenToChanges(event.deviceId);
|
_listenToChanges(event.deviceId);
|
||||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
||||||
@ -36,131 +46,91 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onControl(
|
void _listenToChanges(String deviceId) {
|
||||||
TwoGangSwitchControl event, Emitter<TwoGangSwitchState> emit) async {
|
try {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
|
|
||||||
|
ref.onValue.listen((event) {
|
||||||
|
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
|
||||||
|
List<Status> statusList = [];
|
||||||
|
eventsMap['status'].forEach((element) {
|
||||||
|
statusList.add(
|
||||||
|
Status(code: element['code'], value: element['value']),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus = TwoGangStatusModel.fromJson(deviceId, statusList);
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
});
|
||||||
|
} catch (_) {
|
||||||
|
log(
|
||||||
|
'Error listening to changes',
|
||||||
|
name: 'TwoGangSwitchBloc._listenToChanges',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onControl(
|
||||||
|
TwoGangSwitchControl event,
|
||||||
|
Emitter<TwoGangSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
|
|
||||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
try {
|
||||||
deviceId: event.deviceId,
|
await controlDeviceService.controlDevice(
|
||||||
code: event.code,
|
deviceUuid: event.deviceId,
|
||||||
value: event.value,
|
status: Status(code: event.code, value: event.value),
|
||||||
oldValue: oldValue,
|
);
|
||||||
emit: emit,
|
} catch (e) {
|
||||||
isBatch: false,
|
_updateLocalValue(event.code, !event.value);
|
||||||
);
|
emit(TwoGangSwitchError(e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
Future<void> _onBatchControl(
|
||||||
required dynamic deviceId,
|
TwoGangSwitchBatchControl event,
|
||||||
required String code,
|
Emitter<TwoGangSwitchState> emit,
|
||||||
required bool value,
|
) async {
|
||||||
required bool oldValue,
|
emit(TwoGangSwitchLoading());
|
||||||
required Emitter<TwoGangSwitchState> emit,
|
_updateLocalValue(event.code, event.value);
|
||||||
required bool isBatch,
|
|
||||||
}) async {
|
|
||||||
late String id;
|
|
||||||
|
|
||||||
if (deviceId is List) {
|
|
||||||
id = deviceId.first;
|
|
||||||
} else {
|
|
||||||
id = deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValueAndEmit(id, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
|
||||||
Emitter<TwoGangSwitchState> emit) {
|
|
||||||
_updateLocalValue(code, oldValue);
|
|
||||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
||||||
}
|
|
||||||
|
|
||||||
void _updateLocalValue(String code, bool value) {
|
try {
|
||||||
if (code == 'switch_1') {
|
await batchControlDevicesService.batchControlDevices(
|
||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
uuids: event.deviceId,
|
||||||
}
|
code: event.code,
|
||||||
|
value: event.value,
|
||||||
if (code == 'switch_2') {
|
);
|
||||||
deviceStatus = deviceStatus.copyWith(switch2: value);
|
} catch (e) {
|
||||||
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(TwoGangSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _getValueByCode(String code) {
|
Future<void> _onFetchBatchStatus(
|
||||||
switch (code) {
|
TwoGangSwitchFetchBatchEvent event,
|
||||||
case 'switch_1':
|
Emitter<TwoGangSwitchState> emit,
|
||||||
return deviceStatus.switch1;
|
) async {
|
||||||
case 'switch_2':
|
|
||||||
return deviceStatus.switch2;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(TwoGangSwitchFetchBatchEvent event,
|
|
||||||
Emitter<TwoGangSwitchState> emit) async {
|
|
||||||
emit(TwoGangSwitchLoading());
|
emit(TwoGangSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
deviceStatus = TwoGangStatusModel.fromJson(
|
||||||
deviceStatus =
|
event.devicesIds.first,
|
||||||
TwoGangStatusModel.fromJson(event.devicesIds.first, status.status);
|
status.status,
|
||||||
|
);
|
||||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(TwoGangSwitchError(e.toString()));
|
emit(TwoGangSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
Future<void> _onFactoryReset(
|
||||||
Future<void> close() {
|
TwoGangFactoryReset event,
|
||||||
_timer?.cancel();
|
Emitter<TwoGangSwitchState> emit,
|
||||||
return super.close();
|
) async {
|
||||||
}
|
|
||||||
|
|
||||||
FutureOr<void> _onBatchControl(
|
|
||||||
TwoGangSwitchBatchControl event, Emitter<TwoGangSwitchState> emit) async {
|
|
||||||
final oldValue = _getValueByCode(event.code);
|
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value);
|
|
||||||
|
|
||||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
|
||||||
|
|
||||||
await _runDebounce(
|
|
||||||
deviceId: event.deviceId,
|
|
||||||
code: event.code,
|
|
||||||
value: event.value,
|
|
||||||
oldValue: oldValue,
|
|
||||||
emit: emit,
|
|
||||||
isBatch: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
FutureOr<void> _onFactoryReset(
|
|
||||||
TwoGangFactoryReset event, Emitter<TwoGangSwitchState> emit) async {
|
|
||||||
emit(TwoGangSwitchLoading());
|
emit(TwoGangSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
@ -168,42 +138,31 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
|||||||
event.deviceId,
|
event.deviceId,
|
||||||
);
|
);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(TwoGangSwitchError('Failed'));
|
emit(TwoGangSwitchError('Failed to reset device'));
|
||||||
} else {
|
} else {
|
||||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
add(TwoGangSwitchFetchDeviceEvent(event.deviceId));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(TwoGangSwitchError(e.toString()));
|
emit(TwoGangSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _onStatusUpdated(
|
||||||
try {
|
StatusUpdated event,
|
||||||
DatabaseReference ref =
|
Emitter<TwoGangSwitchState> emit,
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
) {
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
|
||||||
Map<dynamic, dynamic> usersMap =
|
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
|
||||||
|
|
||||||
List<Status> statusList = [];
|
|
||||||
usersMap['status'].forEach((element) {
|
|
||||||
statusList
|
|
||||||
.add(Status(code: element['code'], value: element['value']));
|
|
||||||
});
|
|
||||||
|
|
||||||
deviceStatus =
|
|
||||||
TwoGangStatusModel.fromJson(usersMap['productUuid'], statusList);
|
|
||||||
if (!isClosed) {
|
|
||||||
add(StatusUpdated(deviceStatus));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onStatusUpdated(StatusUpdated event, Emitter<TwoGangSwitchState> emit) {
|
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangSwitchStatusLoaded(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart';
|
||||||
|
|
||||||
|
abstract final class TwoGangSwitchBlocFactory {
|
||||||
|
const TwoGangSwitchBlocFactory._();
|
||||||
|
|
||||||
|
static TwoGangSwitchBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return TwoGangSwitchBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -24,16 +24,16 @@ class TwoGangStatusModel {
|
|||||||
for (var status in jsonList) {
|
for (var status in jsonList) {
|
||||||
switch (status.code) {
|
switch (status.code) {
|
||||||
case 'switch_1':
|
case 'switch_1':
|
||||||
switch1 = status.value ?? false;
|
switch1 = bool.tryParse(status.value.toString()) ?? false;
|
||||||
break;
|
break;
|
||||||
case 'countdown_1':
|
case 'countdown_1':
|
||||||
countDown = status.value ?? 0;
|
countDown = int.tryParse(status.value.toString()) ?? 0;
|
||||||
break;
|
break;
|
||||||
case 'switch_2':
|
case 'switch_2':
|
||||||
switch2 = status.value ?? false;
|
switch2 = bool.tryParse(status.value.toString()) ?? false;
|
||||||
break;
|
break;
|
||||||
case 'countdown_2':
|
case 'countdown_2':
|
||||||
countDown2 = status.value ?? 0;
|
countDown2 = int.tryParse(status.value.toString()) ?? 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.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/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_state.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/factories/two_gang_switch_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/models/two_gang_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/models/two_gang_status_model.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class TwoGangBatchControlView extends StatelessWidget with HelperResponsiveLayou
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => TwoGangSwitchBloc(deviceId: deviceIds.first)
|
create: (context) => TwoGangSwitchBlocFactory.create(deviceId: deviceIds.first)
|
||||||
..add(TwoGangSwitchFetchBatchEvent(deviceIds)),
|
..add(TwoGangSwitchFetchBatchEvent(deviceIds)),
|
||||||
child: BlocBuilder<TwoGangSwitchBloc, TwoGangSwitchState>(
|
child: BlocBuilder<TwoGangSwitchBloc, TwoGangSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_state.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/factories/two_gang_switch_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/models/two_gang_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/two_gang_switch/models/two_gang_status_model.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ class TwoGangDeviceControlView extends StatelessWidget
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => TwoGangSwitchBloc(deviceId: deviceId)
|
create: (context) => TwoGangSwitchBlocFactory.create(deviceId: deviceId)
|
||||||
..add(TwoGangSwitchFetchDeviceEvent(deviceId)),
|
..add(TwoGangSwitchFetchDeviceEvent(deviceId)),
|
||||||
child: BlocBuilder<TwoGangSwitchBloc, TwoGangSwitchState>(
|
child: BlocBuilder<TwoGangSwitchBloc, TwoGangSwitchState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -1,18 +1,28 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.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/wall_sensor/bloc/wall_event.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_state.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_state.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
late WallSensorModel deviceStatus;
|
final ControlDeviceService controlDeviceService;
|
||||||
Timer? _timer;
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
WallSensorBloc({required this.deviceId}) : super(WallSensorInitialState()) {
|
late WallSensorModel deviceStatus;
|
||||||
|
|
||||||
|
WallSensorBloc({
|
||||||
|
required this.deviceId,
|
||||||
|
required this.controlDeviceService,
|
||||||
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(WallSensorInitialState()) {
|
||||||
on<WallSensorFetchStatusEvent>(_fetchWallSensorStatus);
|
on<WallSensorFetchStatusEvent>(_fetchWallSensorStatus);
|
||||||
on<WallSensorFetchBatchStatusEvent>(_fetchWallSensorBatchControl);
|
on<WallSensorFetchBatchStatusEvent>(_fetchWallSensorBatchControl);
|
||||||
on<WallSensorChangeValueEvent>(_changeValue);
|
on<WallSensorChangeValueEvent>(_changeValue);
|
||||||
@ -24,28 +34,28 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
on<WallSensorRealtimeUpdateEvent>(_onRealtimeUpdate);
|
on<WallSensorRealtimeUpdateEvent>(_onRealtimeUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _fetchWallSensorStatus(
|
Future<void> _fetchWallSensorStatus(
|
||||||
WallSensorFetchStatusEvent event, Emitter<WallSensorState> emit) async {
|
WallSensorFetchStatusEvent event,
|
||||||
|
Emitter<WallSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(WallSensorLoadingInitialState());
|
emit(WallSensorLoadingInitialState());
|
||||||
try {
|
try {
|
||||||
var response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
final response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
||||||
deviceStatus = WallSensorModel.fromJson(response.status);
|
deviceStatus = WallSensorModel.fromJson(response.status);
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
|
||||||
_listenToChanges(deviceId);
|
_listenToChanges(deviceId);
|
||||||
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WallSensorFailedState(error: e.toString()));
|
emit(WallSensorFailedState(error: e.toString()));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch batch status
|
Future<void> _fetchWallSensorBatchControl(
|
||||||
FutureOr<void> _fetchWallSensorBatchControl(
|
WallSensorFetchBatchStatusEvent event,
|
||||||
WallSensorFetchBatchStatusEvent event,
|
Emitter<WallSensorState> emit,
|
||||||
Emitter<WallSensorState> emit) async {
|
) async {
|
||||||
emit(WallSensorLoadingInitialState());
|
emit(WallSensorLoadingInitialState());
|
||||||
try {
|
try {
|
||||||
var response =
|
final response = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
|
||||||
deviceStatus = WallSensorModel.fromJson(response.status);
|
deviceStatus = WallSensorModel.fromJson(response.status);
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -54,132 +64,105 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _listenToChanges(String deviceId) {
|
void _listenToChanges(String deviceId) {
|
||||||
DatabaseReference ref =
|
try {
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
ref.onValue.listen((DatabaseEvent event) {
|
|
||||||
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
|
||||||
if (data == null) return;
|
|
||||||
|
|
||||||
final statusList = (data['status'] as List?)
|
ref.onValue.listen((event) {
|
||||||
?.map((e) => Status(code: e['code'], value: e['value']))
|
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (statusList != null) {
|
List<Status> statusList = [];
|
||||||
final updatedDeviceStatus = WallSensorModel.fromJson(statusList);
|
eventsMap['status'].forEach((element) {
|
||||||
|
statusList.add(
|
||||||
|
Status(code: element['code'], value: element['value']),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus = WallSensorModel.fromJson(statusList);
|
||||||
if (!isClosed) {
|
if (!isClosed) {
|
||||||
add(WallSensorRealtimeUpdateEvent(updatedDeviceStatus));
|
add(WallSensorRealtimeUpdateEvent(deviceStatus));
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
} catch (_) {
|
||||||
|
log(
|
||||||
|
'Error listening to changes',
|
||||||
|
name: 'WallSensorBloc._listenToChanges',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _changeValue(
|
||||||
void _changeValue(
|
WallSensorChangeValueEvent event,
|
||||||
WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
|
Emitter<WallSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
||||||
if (event.code == 'far_detection') {
|
_updateLocalValue(event.code, event.value);
|
||||||
deviceStatus.farDetection = event.value;
|
|
||||||
} else if (event.code == 'motionless_sensitivity') {
|
|
||||||
deviceStatus.motionlessSensitivity = event.value;
|
|
||||||
} else if (event.code == 'motion_sensitivity_value') {
|
|
||||||
deviceStatus.motionSensitivity = event.value;
|
|
||||||
} else if (event.code == 'no_one_time') {
|
|
||||||
deviceStatus.noBodyTime = event.value;
|
|
||||||
}
|
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
await _runDeBouncer(
|
|
||||||
deviceId: deviceId,
|
try {
|
||||||
code: event.code,
|
await controlDeviceService.controlDevice(
|
||||||
value: event.value,
|
deviceUuid: deviceId,
|
||||||
isBatch: false,
|
status: Status(code: event.code, value: event.value),
|
||||||
emit: emit,
|
);
|
||||||
);
|
} catch (e) {
|
||||||
|
_updateLocalValue(event.code, event.value == 0 ? 1 : 0);
|
||||||
|
emit(WallSensorFailedState(error: e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(
|
Future<void> _onBatchControl(
|
||||||
WallSensorBatchControlEvent event, Emitter<WallSensorState> emit) async {
|
WallSensorBatchControlEvent event,
|
||||||
|
Emitter<WallSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
||||||
if (event.code == 'far_detection') {
|
_updateLocalValue(event.code, event.value);
|
||||||
deviceStatus.farDetection = event.value;
|
|
||||||
} else if (event.code == 'motionless_sensitivity') {
|
|
||||||
deviceStatus.motionlessSensitivity = event.value;
|
|
||||||
} else if (event.code == 'motion_sensitivity_value') {
|
|
||||||
deviceStatus.motionSensitivity = event.value;
|
|
||||||
} else if (event.code == 'no_one_time') {
|
|
||||||
deviceStatus.noBodyTime = event.value;
|
|
||||||
}
|
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
await _runDeBouncer(
|
|
||||||
deviceId: event.deviceIds,
|
|
||||||
code: event.code,
|
|
||||||
value: event.value,
|
|
||||||
emit: emit,
|
|
||||||
isBatch: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_runDeBouncer({
|
|
||||||
required dynamic deviceId,
|
|
||||||
required String code,
|
|
||||||
required dynamic value,
|
|
||||||
required Emitter<WallSensorState> emit,
|
|
||||||
required bool isBatch,
|
|
||||||
}) {
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
_timer = Timer(const Duration(seconds: 1), () async {
|
|
||||||
try {
|
|
||||||
late bool response;
|
|
||||||
if (isBatch) {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceBatchControl(deviceId, code, value);
|
|
||||||
} else {
|
|
||||||
response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
add(WallSensorFetchStatusEvent());
|
|
||||||
}
|
|
||||||
} catch (_) {
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
add(WallSensorFetchStatusEvent());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
FutureOr<void> _getDeviceReports(
|
|
||||||
GetDeviceReportsEvent event, Emitter<WallSensorState> emit) async {
|
|
||||||
emit(DeviceReportsLoadingState());
|
|
||||||
// final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch;
|
|
||||||
// final to = DateTime.now().millisecondsSinceEpoch;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// await DevicesManagementApi.getDeviceReportsByDate(
|
await batchControlDevicesService.batchControlDevices(
|
||||||
// deviceId, event.code, from.toString(), to.toString())
|
uuids: event.deviceIds,
|
||||||
await DevicesManagementApi.getDeviceReports(deviceId, event.code)
|
code: event.code,
|
||||||
.then((value) {
|
value: event.value,
|
||||||
emit(DeviceReportsState(deviceReport: value, code: event.code));
|
);
|
||||||
});
|
} catch (e) {
|
||||||
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(WallSensorFailedState(error: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _getDeviceReports(
|
||||||
|
GetDeviceReportsEvent event,
|
||||||
|
Emitter<WallSensorState> emit,
|
||||||
|
) async {
|
||||||
|
emit(DeviceReportsLoadingState());
|
||||||
|
try {
|
||||||
|
final reports = await DevicesManagementApi.getDeviceReports(
|
||||||
|
deviceId,
|
||||||
|
event.code,
|
||||||
|
);
|
||||||
|
emit(DeviceReportsState(deviceReport: reports, code: event.code));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(DeviceReportsFailedState(error: e.toString()));
|
emit(DeviceReportsFailedState(error: e.toString()));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showDescription(
|
void _showDescription(
|
||||||
ShowDescriptionEvent event, Emitter<WallSensorState> emit) {
|
ShowDescriptionEvent event,
|
||||||
|
Emitter<WallSensorState> emit,
|
||||||
|
) {
|
||||||
emit(WallSensorShowDescriptionState(description: event.description));
|
emit(WallSensorShowDescriptionState(description: event.description));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _backToGridView(
|
void _backToGridView(
|
||||||
BackToGridViewEvent event, Emitter<WallSensorState> emit) {
|
BackToGridViewEvent event,
|
||||||
|
Emitter<WallSensorState> emit,
|
||||||
|
) {
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFactoryReset(
|
Future<void> _onFactoryReset(
|
||||||
WallSensorFactoryResetEvent event, Emitter<WallSensorState> emit) async {
|
WallSensorFactoryResetEvent event,
|
||||||
|
Emitter<WallSensorState> emit,
|
||||||
|
) async {
|
||||||
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
@ -187,9 +170,9 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
event.deviceId,
|
event.deviceId,
|
||||||
);
|
);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
emit(const WallSensorFailedState(error: 'Failed'));
|
emit(const WallSensorFailedState(error: 'Failed to reset device'));
|
||||||
} else {
|
} else {
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
add(WallSensorFetchStatusEvent());
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WallSensorFailedState(error: e.toString()));
|
emit(WallSensorFailedState(error: e.toString()));
|
||||||
@ -200,7 +183,23 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
WallSensorRealtimeUpdateEvent event,
|
WallSensorRealtimeUpdateEvent event,
|
||||||
Emitter<WallSensorState> emit,
|
Emitter<WallSensorState> emit,
|
||||||
) {
|
) {
|
||||||
deviceStatus = event.deviceStatus;
|
emit(WallSensorUpdateState(wallSensorModel: event.deviceStatus));
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
}
|
||||||
|
|
||||||
|
void _updateLocalValue(String code, dynamic value) {
|
||||||
|
switch (code) {
|
||||||
|
case 'far_detection':
|
||||||
|
deviceStatus.farDetection = value;
|
||||||
|
break;
|
||||||
|
case 'motionless_sensitivity':
|
||||||
|
deviceStatus.motionlessSensitivity = value;
|
||||||
|
break;
|
||||||
|
case 'motion_sensitivity_value':
|
||||||
|
deviceStatus.motionSensitivity = value;
|
||||||
|
break;
|
||||||
|
case 'no_one_time':
|
||||||
|
deviceStatus.noBodyTime = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_bloc.dart';
|
||||||
|
|
||||||
|
abstract final class WallSensorBlocFactory {
|
||||||
|
const WallSensorBlocFactory._();
|
||||||
|
|
||||||
|
static WallSensorBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return WallSensorBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presen
|
|||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_state.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/factories/wall_sensor_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ class WallSensorBatchControlView extends StatelessWidget with HelperResponsiveLa
|
|||||||
final isLarge = isLargeScreenSize(context);
|
final isLarge = isLargeScreenSize(context);
|
||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => WallSensorBloc(deviceId: devicesIds.first)
|
create: (context) => WallSensorBlocFactory.create(deviceId: devicesIds.first)
|
||||||
..add(WallSensorFetchBatchStatusEvent(devicesIds)),
|
..add(WallSensorFetchBatchStatusEvent(devicesIds)),
|
||||||
child: BlocBuilder<WallSensorBloc, WallSensorState>(
|
child: BlocBuilder<WallSensorBloc, WallSensorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -10,6 +10,7 @@ import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presen
|
|||||||
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_static_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_static_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_status.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_update_data.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_update_data.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/factories/wall_sensor_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
@ -26,7 +27,7 @@ class WallSensorControlsView extends StatelessWidget with HelperResponsiveLayout
|
|||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
WallSensorBloc(deviceId: device.uuid!)..add(WallSensorFetchStatusEvent()),
|
WallSensorBlocFactory.create(deviceId: device.uuid!)..add(WallSensorFetchStatusEvent()),
|
||||||
child: BlocBuilder<WallSensorBloc, WallSensorState>(
|
child: BlocBuilder<WallSensorBloc, WallSensorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is WallSensorLoadingInitialState || state is DeviceReportsLoadingState) {
|
if (state is WallSensorLoadingInitialState || state is DeviceReportsLoadingState) {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// water_heater_bloc.dart
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
@ -10,6 +8,8 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_sta
|
|||||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_entry.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_entry.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_model.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.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/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/format_date_time.dart';
|
import 'package:syncrow_web/utils/format_date_time.dart';
|
||||||
|
|
||||||
@ -17,7 +17,17 @@ part 'water_heater_event.dart';
|
|||||||
part 'water_heater_state.dart';
|
part 'water_heater_state.dart';
|
||||||
|
|
||||||
class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||||
WaterHeaterBloc() : super(WaterHeaterInitial()) {
|
late WaterHeaterStatusModel deviceStatus;
|
||||||
|
final String deviceId;
|
||||||
|
final ControlDeviceService controlDeviceService;
|
||||||
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
Timer? _countdownTimer;
|
||||||
|
|
||||||
|
WaterHeaterBloc({
|
||||||
|
required this.deviceId,
|
||||||
|
required this.controlDeviceService,
|
||||||
|
required this.batchControlDevicesService,
|
||||||
|
}) : super(WaterHeaterInitial()) {
|
||||||
on<WaterHeaterFetchStatusEvent>(_fetchWaterHeaterStatus);
|
on<WaterHeaterFetchStatusEvent>(_fetchWaterHeaterStatus);
|
||||||
on<ToggleWaterHeaterEvent>(_controlWaterHeater);
|
on<ToggleWaterHeaterEvent>(_controlWaterHeater);
|
||||||
on<FetchWaterHeaterBatchStatusEvent>(_batchFetchWaterHeater);
|
on<FetchWaterHeaterBatchStatusEvent>(_batchFetchWaterHeater);
|
||||||
@ -29,7 +39,6 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
on<UpdateSelectedTimeEvent>(_updateSelectedTime);
|
on<UpdateSelectedTimeEvent>(_updateSelectedTime);
|
||||||
on<UpdateSelectedDayEvent>(_updateSelectedDay);
|
on<UpdateSelectedDayEvent>(_updateSelectedDay);
|
||||||
on<UpdateFunctionOnEvent>(_updateFunctionOn);
|
on<UpdateFunctionOnEvent>(_updateFunctionOn);
|
||||||
|
|
||||||
on<GetSchedulesEvent>(_getSchedule);
|
on<GetSchedulesEvent>(_getSchedule);
|
||||||
on<AddScheduleEvent>(_onAddSchedule);
|
on<AddScheduleEvent>(_onAddSchedule);
|
||||||
on<EditWaterHeaterScheduleEvent>(_onEditSchedule);
|
on<EditWaterHeaterScheduleEvent>(_onEditSchedule);
|
||||||
@ -38,11 +47,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
late WaterHeaterStatusModel deviceStatus;
|
void _initializeAddSchedule(
|
||||||
Timer? _countdownTimer;
|
|
||||||
// Timer? _inchingTimer;
|
|
||||||
|
|
||||||
FutureOr<void> _initializeAddSchedule(
|
|
||||||
InitializeAddScheduleEvent event,
|
InitializeAddScheduleEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) {
|
) {
|
||||||
@ -64,7 +69,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _updateSelectedTime(
|
void _updateSelectedTime(
|
||||||
UpdateSelectedTimeEvent event,
|
UpdateSelectedTimeEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) {
|
) {
|
||||||
@ -73,7 +78,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
emit(currentState.copyWith(selectedTime: event.selectedTime));
|
emit(currentState.copyWith(selectedTime: event.selectedTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _updateSelectedDay(
|
void _updateSelectedDay(
|
||||||
UpdateSelectedDayEvent event,
|
UpdateSelectedDayEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) {
|
) {
|
||||||
@ -84,7 +89,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _updateFunctionOn(
|
void _updateFunctionOn(
|
||||||
UpdateFunctionOnEvent event,
|
UpdateFunctionOnEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) {
|
) {
|
||||||
@ -93,16 +98,18 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
functionOn: event.isOn, selectedTime: currentState.selectedTime));
|
functionOn: event.isOn, selectedTime: currentState.selectedTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _updateScheduleEvent(
|
Future<void> _updateScheduleEvent(
|
||||||
UpdateScheduleEvent event,
|
UpdateScheduleEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) async {
|
) async {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is WaterHeaterDeviceStatusLoaded) {
|
if (currentState is WaterHeaterDeviceStatusLoaded) {
|
||||||
if (event.scheduleMode == ScheduleModes.schedule) {
|
if (event.scheduleMode == ScheduleModes.schedule) {
|
||||||
emit(currentState.copyWith(
|
emit(
|
||||||
scheduleMode: ScheduleModes.schedule,
|
currentState.copyWith(
|
||||||
));
|
scheduleMode: ScheduleModes.schedule,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (event.scheduleMode == ScheduleModes.countdown) {
|
if (event.scheduleMode == ScheduleModes.countdown) {
|
||||||
final countdownRemaining =
|
final countdownRemaining =
|
||||||
@ -116,87 +123,88 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
countdownRemaining: countdownRemaining,
|
countdownRemaining: countdownRemaining,
|
||||||
));
|
));
|
||||||
|
|
||||||
if (!currentState.isCountdownActive! &&
|
if (!currentState.isCountdownActive! && countdownRemaining > Duration.zero) {
|
||||||
countdownRemaining > Duration.zero) {
|
|
||||||
_startCountdownTimer(emit, countdownRemaining);
|
_startCountdownTimer(emit, countdownRemaining);
|
||||||
}
|
}
|
||||||
} else if (event.scheduleMode == ScheduleModes.inching) {
|
} else if (event.scheduleMode == ScheduleModes.inching) {
|
||||||
final inchingDuration =
|
final inchingDuration = Duration(hours: event.hours, minutes: event.minutes);
|
||||||
Duration(hours: event.hours, minutes: event.minutes);
|
|
||||||
|
|
||||||
emit(currentState.copyWith(
|
emit(
|
||||||
scheduleMode: ScheduleModes.inching,
|
currentState.copyWith(
|
||||||
inchingHours: inchingDuration.inHours,
|
scheduleMode: ScheduleModes.inching,
|
||||||
inchingMinutes: inchingDuration.inMinutes % 60,
|
inchingHours: inchingDuration.inHours,
|
||||||
isInchingActive: currentState.isInchingActive,
|
inchingMinutes: inchingDuration.inMinutes % 60,
|
||||||
));
|
isInchingActive: currentState.isInchingActive,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _controlWaterHeater(
|
Future<void> _controlWaterHeater(
|
||||||
ToggleWaterHeaterEvent event,
|
ToggleWaterHeaterEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) async {
|
) async {
|
||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
final oldValue = _getValueByCode(event.code);
|
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
|
|
||||||
emit(currentState.copyWith(
|
emit(
|
||||||
status: deviceStatus,
|
currentState.copyWith(
|
||||||
));
|
status: deviceStatus,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
final success = await _runDebounce(
|
final success = await controlDeviceService.controlDevice(
|
||||||
deviceId: event.deviceId,
|
deviceUuid: event.deviceId,
|
||||||
code: event.code,
|
status: Status(
|
||||||
value: event.value,
|
code: event.code,
|
||||||
oldValue: oldValue,
|
value: event.value,
|
||||||
emit: emit,
|
),
|
||||||
isBatch: false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (event.code == "countdown_1") {
|
if (event.code == "countdown_1") {
|
||||||
final countdownDuration = Duration(seconds: event.value);
|
final countdownDuration = Duration(seconds: event.value);
|
||||||
|
|
||||||
emit(currentState.copyWith(
|
emit(
|
||||||
countdownHours: countdownDuration.inHours,
|
currentState.copyWith(
|
||||||
countdownMinutes: countdownDuration.inMinutes % 60,
|
countdownHours: countdownDuration.inHours,
|
||||||
countdownRemaining: countdownDuration,
|
countdownMinutes: countdownDuration.inMinutes % 60,
|
||||||
isCountdownActive: true,
|
countdownRemaining: countdownDuration,
|
||||||
));
|
isCountdownActive: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (countdownDuration.inSeconds > 0) {
|
if (countdownDuration.inSeconds > 0) {
|
||||||
_startCountdownTimer(emit, countdownDuration);
|
_startCountdownTimer(emit, countdownDuration);
|
||||||
} else {
|
} else {
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
emit(currentState.copyWith(
|
emit(
|
||||||
countdownHours: 0,
|
currentState.copyWith(
|
||||||
countdownMinutes: 0,
|
countdownHours: 0,
|
||||||
countdownRemaining: Duration.zero,
|
countdownMinutes: 0,
|
||||||
isCountdownActive: false,
|
countdownRemaining: Duration.zero,
|
||||||
));
|
isCountdownActive: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (event.code == "switch_inching") {
|
} else if (event.code == "switch_inching") {
|
||||||
final inchingDuration = Duration(seconds: event.value);
|
final inchingDuration = Duration(seconds: event.value);
|
||||||
//if (inchingDuration.inSeconds > 0) {
|
emit(
|
||||||
// _startInchingTimer(emit, inchingDuration);
|
currentState.copyWith(
|
||||||
// } else {
|
inchingHours: inchingDuration.inHours,
|
||||||
emit(currentState.copyWith(
|
inchingMinutes: inchingDuration.inMinutes % 60,
|
||||||
inchingHours: inchingDuration.inHours,
|
isInchingActive: true,
|
||||||
inchingMinutes: inchingDuration.inMinutes % 60,
|
),
|
||||||
isInchingActive: true,
|
);
|
||||||
));
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _stopScheduleEvent(
|
Future<void> _stopScheduleEvent(
|
||||||
StopScheduleEvent event,
|
StopScheduleEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) async {
|
) async {
|
||||||
@ -207,25 +215,28 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
|
|
||||||
if (isCountDown) {
|
if (isCountDown) {
|
||||||
emit(currentState.copyWith(
|
emit(
|
||||||
countdownHours: 0,
|
currentState.copyWith(
|
||||||
countdownMinutes: 0,
|
countdownHours: 0,
|
||||||
countdownRemaining: Duration.zero,
|
countdownMinutes: 0,
|
||||||
isCountdownActive: false,
|
countdownRemaining: Duration.zero,
|
||||||
));
|
isCountdownActive: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
} else if (currentState.scheduleMode == ScheduleModes.inching) {
|
} else if (currentState.scheduleMode == ScheduleModes.inching) {
|
||||||
emit(currentState.copyWith(
|
emit(
|
||||||
inchingHours: 0,
|
currentState.copyWith(
|
||||||
inchingMinutes: 0,
|
inchingHours: 0,
|
||||||
isInchingActive: false,
|
inchingMinutes: 0,
|
||||||
));
|
isInchingActive: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().deviceControl(
|
final status = await DevicesManagementApi().deviceControl(
|
||||||
event.deviceId,
|
event.deviceId,
|
||||||
Status(
|
Status(code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
|
||||||
code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
|
|
||||||
);
|
);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.'));
|
emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.'));
|
||||||
@ -236,17 +247,15 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _fetchWaterHeaterStatus(
|
Future<void> _fetchWaterHeaterStatus(
|
||||||
WaterHeaterFetchStatusEvent event,
|
WaterHeaterFetchStatusEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) async {
|
) async {
|
||||||
emit(WaterHeaterLoadingState());
|
emit(WaterHeaterLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
deviceStatus = WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||||
deviceStatus =
|
|
||||||
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
|
||||||
|
|
||||||
if (deviceStatus.scheduleMode == ScheduleModes.countdown) {
|
if (deviceStatus.scheduleMode == ScheduleModes.countdown) {
|
||||||
final countdownRemaining = Duration(
|
final countdownRemaining = Duration(
|
||||||
@ -288,7 +297,6 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
inchingMinutes: deviceStatus.inchingMinutes,
|
inchingMinutes: deviceStatus.inchingMinutes,
|
||||||
isInchingActive: true,
|
isInchingActive: true,
|
||||||
));
|
));
|
||||||
//_startInchingTimer(emit, inchingDuration);
|
|
||||||
} else {
|
} else {
|
||||||
emit(WaterHeaterDeviceStatusLoaded(
|
emit(WaterHeaterDeviceStatusLoaded(
|
||||||
deviceStatus,
|
deviceStatus,
|
||||||
@ -316,7 +324,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _listenToChanges(deviceId) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
DatabaseReference ref =
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
@ -328,12 +336,11 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
|
|
||||||
List<Status> statusList = [];
|
List<Status> statusList = [];
|
||||||
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 = WaterHeaterStatusModel.fromJson(
|
deviceStatus =
|
||||||
usersMap['productUuid'], statusList);
|
WaterHeaterStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
if (!isClosed) {
|
if (!isClosed) {
|
||||||
add(StatusUpdated(deviceStatus));
|
add(StatusUpdated(deviceStatus));
|
||||||
}
|
}
|
||||||
@ -341,7 +348,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(StatusUpdated event, Emitter<WaterHeaterState> emit) {
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event,
|
||||||
|
Emitter<WaterHeaterState> emit,
|
||||||
|
) {
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
@ -352,23 +362,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
) {
|
) {
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
|
|
||||||
_countdownTimer = Timer.periodic(const Duration(minutes: 1), (timer) {
|
_countdownTimer = Timer.periodic(
|
||||||
add(DecrementCountdownEvent());
|
const Duration(minutes: 1),
|
||||||
});
|
(timer) => add(DecrementCountdownEvent()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void _startInchingTimer(
|
void _onDecrementCountdown(
|
||||||
// Emitter<WaterHeaterState> emit,
|
|
||||||
// Duration inchingDuration,
|
|
||||||
// ) {
|
|
||||||
// _inchingTimer?.cancel();
|
|
||||||
|
|
||||||
// _inchingTimer = Timer.periodic(const Duration(minutes: 1), (timer) {
|
|
||||||
// add(DecrementInchingEvent());
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
_onDecrementCountdown(
|
|
||||||
DecrementCountdownEvent event,
|
DecrementCountdownEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) {
|
) {
|
||||||
@ -382,105 +382,29 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
|
|
||||||
if (newRemaining <= Duration.zero) {
|
if (newRemaining <= Duration.zero) {
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
emit(currentState.copyWith(
|
emit(
|
||||||
countdownHours: 0,
|
currentState.copyWith(
|
||||||
countdownMinutes: 0,
|
countdownHours: 0,
|
||||||
isCountdownActive: false,
|
countdownMinutes: 0,
|
||||||
countdownRemaining: Duration.zero,
|
isCountdownActive: false,
|
||||||
));
|
countdownRemaining: Duration.zero,
|
||||||
|
),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int totalSeconds = newRemaining.inSeconds;
|
final totalSeconds = newRemaining.inSeconds;
|
||||||
|
final newHours = totalSeconds ~/ 3600;
|
||||||
|
final newMinutes = (totalSeconds % 3600) ~/ 60;
|
||||||
|
|
||||||
int newHours = totalSeconds ~/ 3600;
|
emit(
|
||||||
int newMinutes = (totalSeconds % 3600) ~/ 60;
|
currentState.copyWith(
|
||||||
|
countdownHours: newHours,
|
||||||
emit(currentState.copyWith(
|
countdownMinutes: newMinutes,
|
||||||
countdownHours: newHours,
|
countdownRemaining: newRemaining,
|
||||||
countdownMinutes: newMinutes,
|
),
|
||||||
countdownRemaining: newRemaining,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FutureOr<void> _onDecrementInching(
|
|
||||||
// DecrementInchingEvent event,
|
|
||||||
// Emitter<WaterHeaterState> emit,
|
|
||||||
// ) {
|
|
||||||
// if (state is WaterHeaterDeviceStatusLoaded) {
|
|
||||||
// final currentState = state as WaterHeaterDeviceStatusLoaded;
|
|
||||||
|
|
||||||
// if (currentState.inchingHours > 0 || currentState.inchingMinutes > 0) {
|
|
||||||
// final newRemaining = Duration(
|
|
||||||
// hours: currentState.inchingHours,
|
|
||||||
// minutes: currentState.inchingMinutes,
|
|
||||||
// ) -
|
|
||||||
// const Duration(minutes: 1);
|
|
||||||
|
|
||||||
// if (newRemaining <= Duration.zero) {
|
|
||||||
// _inchingTimer?.cancel();
|
|
||||||
// emit(currentState.copyWith(
|
|
||||||
// inchingHours: 0,
|
|
||||||
// inchingMinutes: 0,
|
|
||||||
// isInchingActive: false,
|
|
||||||
// ));
|
|
||||||
// } else {
|
|
||||||
// emit(currentState.copyWith(
|
|
||||||
// inchingHours: newRemaining.inHours,
|
|
||||||
// inchingMinutes: newRemaining.inMinutes % 60,
|
|
||||||
// ));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Future<bool> _runDebounce({
|
|
||||||
required dynamic deviceId,
|
|
||||||
required String code,
|
|
||||||
required dynamic value,
|
|
||||||
required dynamic oldValue,
|
|
||||||
required Emitter<WaterHeaterState> emit,
|
|
||||||
required bool isBatch,
|
|
||||||
}) async {
|
|
||||||
try {
|
|
||||||
late bool status;
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
|
|
||||||
if (isBatch) {
|
|
||||||
status = await DevicesManagementApi().deviceBatchControl(
|
|
||||||
deviceId,
|
|
||||||
code,
|
|
||||||
value,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
status = await DevicesManagementApi().deviceControl(
|
|
||||||
deviceId,
|
|
||||||
Status(code: code, value: value),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!status) {
|
|
||||||
_revertValue(code, oldValue, emit.call);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValue(code, oldValue, emit.call);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValue(String code, dynamic oldValue,
|
|
||||||
void Function(WaterHeaterState state) emit) {
|
|
||||||
_updateLocalValue(code, oldValue);
|
|
||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
|
||||||
emit(currentState.copyWith(
|
|
||||||
status: deviceStatus,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,14 +429,12 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dynamic _getValueByCode(String code) {
|
dynamic _getValueByCode(String code) {
|
||||||
switch (code) {
|
return switch (code) {
|
||||||
case 'switch_1':
|
'switch_1' => deviceStatus.heaterSwitch,
|
||||||
return deviceStatus.heaterSwitch;
|
'countdown_1' =>
|
||||||
case 'countdown_1':
|
(deviceStatus.countdownHours * 60) + deviceStatus.countdownMinutes,
|
||||||
return deviceStatus.countdownHours * 60 + deviceStatus.countdownMinutes;
|
_ => null,
|
||||||
default:
|
};
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -521,13 +443,17 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _getSchedule(
|
Future<void> _getSchedule(
|
||||||
GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
|
GetSchedulesEvent event,
|
||||||
|
Emitter<WaterHeaterState> emit,
|
||||||
|
) async {
|
||||||
emit(ScheduleLoadingState());
|
emit(ScheduleLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<ScheduleModel> schedules = await DevicesManagementApi()
|
final schedules = await DevicesManagementApi().getDeviceSchedules(
|
||||||
.getDeviceSchedules(deviceStatus.uuid, event.category);
|
deviceStatus.uuid,
|
||||||
|
event.category,
|
||||||
|
);
|
||||||
|
|
||||||
emit(WaterHeaterDeviceStatusLoaded(
|
emit(WaterHeaterDeviceStatusLoaded(
|
||||||
deviceStatus,
|
deviceStatus,
|
||||||
@ -535,7 +461,6 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
scheduleMode: ScheduleModes.schedule,
|
scheduleMode: ScheduleModes.schedule,
|
||||||
));
|
));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//(const WaterHeaterFailedState(error: 'Failed to fetch schedules.'));
|
|
||||||
emit(WaterHeaterDeviceStatusLoaded(
|
emit(WaterHeaterDeviceStatusLoaded(
|
||||||
deviceStatus,
|
deviceStatus,
|
||||||
schedules: const [],
|
schedules: const [],
|
||||||
@ -543,7 +468,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onAddSchedule(
|
Future<void> _onAddSchedule(
|
||||||
AddScheduleEvent event,
|
AddScheduleEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) async {
|
) async {
|
||||||
@ -557,8 +482,6 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
||||||
);
|
);
|
||||||
|
|
||||||
// emit(ScheduleLoadingState());
|
|
||||||
|
|
||||||
bool success = await DevicesManagementApi()
|
bool success = await DevicesManagementApi()
|
||||||
.addScheduleRecord(newSchedule, currentState.status.uuid);
|
.addScheduleRecord(newSchedule, currentState.status.uuid);
|
||||||
|
|
||||||
@ -566,13 +489,14 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
|
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
|
||||||
} else {
|
} else {
|
||||||
emit(currentState);
|
emit(currentState);
|
||||||
//emit(const WaterHeaterFailedState(error: 'Failed to add schedule.'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onEditSchedule(EditWaterHeaterScheduleEvent event,
|
Future<void> _onEditSchedule(
|
||||||
Emitter<WaterHeaterState> emit) async {
|
EditWaterHeaterScheduleEvent event,
|
||||||
|
Emitter<WaterHeaterState> emit,
|
||||||
|
) async {
|
||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
@ -584,8 +508,6 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
||||||
);
|
);
|
||||||
|
|
||||||
// emit(ScheduleLoadingState());
|
|
||||||
|
|
||||||
bool success = await DevicesManagementApi().editScheduleRecord(
|
bool success = await DevicesManagementApi().editScheduleRecord(
|
||||||
currentState.status.uuid,
|
currentState.status.uuid,
|
||||||
newSchedule,
|
newSchedule,
|
||||||
@ -595,12 +517,11 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
|
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
|
||||||
} else {
|
} else {
|
||||||
emit(currentState);
|
emit(currentState);
|
||||||
//emit(const WaterHeaterFailedState(error: 'Failed to add schedule.'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onUpdateSchedule(
|
Future<void> _onUpdateSchedule(
|
||||||
UpdateScheduleEntryEvent event,
|
UpdateScheduleEntryEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) async {
|
) async {
|
||||||
@ -627,20 +548,17 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
emit(currentState.copyWith(schedules: updatedSchedules));
|
emit(currentState.copyWith(schedules: updatedSchedules));
|
||||||
} else {
|
} else {
|
||||||
emit(currentState);
|
emit(currentState);
|
||||||
// emit(const WaterHeaterFailedState(error: 'Failed to update schedule.'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onDeleteSchedule(
|
Future<void> _onDeleteSchedule(
|
||||||
DeleteScheduleEvent event,
|
DeleteScheduleEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) async {
|
) async {
|
||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
// emit(ScheduleLoadingState());
|
|
||||||
|
|
||||||
bool success = await DevicesManagementApi()
|
bool success = await DevicesManagementApi()
|
||||||
.deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
|
.deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
|
||||||
|
|
||||||
@ -652,20 +570,22 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
emit(currentState.copyWith(schedules: updatedSchedules));
|
emit(currentState.copyWith(schedules: updatedSchedules));
|
||||||
} else {
|
} else {
|
||||||
emit(currentState);
|
emit(currentState);
|
||||||
// emit(const WaterHeaterFailedState(error: 'Failed to delete schedule.'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event,
|
Future<void> _batchFetchWaterHeater(
|
||||||
Emitter<WaterHeaterState> emit) async {
|
FetchWaterHeaterBatchStatusEvent event,
|
||||||
|
Emitter<WaterHeaterState> emit,
|
||||||
|
) async {
|
||||||
emit(WaterHeaterLoadingState());
|
emit(WaterHeaterLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final status =
|
final status = await DevicesManagementApi().getBatchStatus(
|
||||||
await DevicesManagementApi().getBatchStatus(event.devicesUuid);
|
event.devicesUuid,
|
||||||
deviceStatus = WaterHeaterStatusModel.fromJson(
|
);
|
||||||
event.devicesUuid.first, status.status);
|
deviceStatus =
|
||||||
|
WaterHeaterStatusModel.fromJson(event.devicesUuid.first, status.status);
|
||||||
|
|
||||||
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -673,8 +593,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event,
|
Future<void> _batchControlWaterHeater(
|
||||||
Emitter<WaterHeaterState> emit) async {
|
ControlWaterHeaterBatchEvent event, Emitter<WaterHeaterState> emit) async {
|
||||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
@ -686,13 +606,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
status: deviceStatus,
|
status: deviceStatus,
|
||||||
));
|
));
|
||||||
|
|
||||||
final success = await _runDebounce(
|
final success = await batchControlDevicesService.batchControlDevices(
|
||||||
deviceId: event.devicesUuid,
|
uuids: event.devicesUuid,
|
||||||
code: event.code,
|
code: event.code,
|
||||||
value: event.value,
|
value: event.value,
|
||||||
oldValue: oldValue,
|
|
||||||
emit: emit,
|
|
||||||
isBatch: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// water_heater_state.dart
|
|
||||||
|
|
||||||
part of 'water_heater_bloc.dart';
|
part of 'water_heater_bloc.dart';
|
||||||
|
|
||||||
sealed class WaterHeaterState extends Equatable {
|
sealed class WaterHeaterState extends Equatable {
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
|
||||||
|
|
||||||
|
abstract final class WaterHeaterBlocFactory {
|
||||||
|
const WaterHeaterBlocFactory._();
|
||||||
|
|
||||||
|
static WaterHeaterBloc create({
|
||||||
|
required String deviceId,
|
||||||
|
}) {
|
||||||
|
return WaterHeaterBloc(
|
||||||
|
deviceId: deviceId,
|
||||||
|
controlDeviceService:
|
||||||
|
DeviceBlocDependenciesFactory.createControlDeviceService(),
|
||||||
|
batchControlDevicesService:
|
||||||
|
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,16 @@
|
|||||||
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:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/water_heater/factories/water_heater_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class WaterHEaterBatchControlView extends StatelessWidget with HelperResponsiveLayout {
|
class WaterHEaterBatchControlView extends StatelessWidget
|
||||||
|
with HelperResponsiveLayout {
|
||||||
const WaterHEaterBatchControlView({super.key, required this.deviceIds});
|
const WaterHEaterBatchControlView({super.key, required this.deviceIds});
|
||||||
|
|
||||||
final List<String> deviceIds;
|
final List<String> deviceIds;
|
||||||
@ -17,8 +18,9 @@ class WaterHEaterBatchControlView extends StatelessWidget with HelperResponsiveL
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) => WaterHeaterBlocFactory.create(
|
||||||
WaterHeaterBloc()..add(FetchWaterHeaterBatchStatusEvent(devicesUuid: deviceIds)),
|
deviceId: deviceIds.first,
|
||||||
|
)..add(FetchWaterHeaterBatchStatusEvent(devicesUuid: deviceIds)),
|
||||||
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is WaterHeaterLoadingState) {
|
if (state is WaterHeaterLoadingState) {
|
||||||
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
|||||||
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/water_heater/factories/water_heater_bloc_factory.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/water_heater/widgets/schedual_view.dart';
|
import 'package:syncrow_web/pages/device_managment/water_heater/widgets/schedual_view.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
@ -21,8 +22,9 @@ class WaterHeaterDeviceControlView extends StatelessWidget
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) => WaterHeaterBlocFactory.create(
|
||||||
WaterHeaterBloc()..add(WaterHeaterFetchStatusEvent(device.uuid!)),
|
deviceId: device.uuid ?? '',
|
||||||
|
)..add(WaterHeaterFetchStatusEvent(device.uuid!)),
|
||||||
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is WaterHeaterLoadingState) {
|
if (state is WaterHeaterLoadingState) {
|
||||||
@ -33,8 +35,7 @@ class WaterHeaterDeviceControlView extends StatelessWidget
|
|||||||
state is WaterHeaterBatchFailedState) {
|
state is WaterHeaterBatchFailedState) {
|
||||||
return const Center(child: Text('Error fetching status'));
|
return const Center(child: Text('Error fetching status'));
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox(
|
return const SizedBox(height: 200, child: Center(child: SizedBox()));
|
||||||
height: 200, child: Center(child: SizedBox()));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
Reference in New Issue
Block a user