mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
Implement a countdown timer for the AC and fix bugs in the 'Forgot Password'
This commit is contained in:
@ -13,6 +13,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
late AcStatusModel deviceStatus;
|
||||
final String deviceId;
|
||||
Timer? _timer;
|
||||
Timer? _countdownTimer;
|
||||
|
||||
AcBloc({required this.deviceId}) : super(AcsInitialState()) {
|
||||
on<AcFetchDeviceStatusEvent>(_onFetchAcStatus);
|
||||
@ -21,7 +22,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
on<AcBatchControlEvent>(_onAcBatchControl);
|
||||
on<AcFactoryResetEvent>(_onFactoryReset);
|
||||
on<AcStatusUpdated>(_onAcStatusUpdated);
|
||||
on<OnClose>(_onClose);
|
||||
on<IncreaseTimeEvent>(_handleIncreaseTime);
|
||||
on<DecreaseTimeEvent>(_handleDecreaseTime);
|
||||
on<UpdateTimerEvent>(_handleUpdateTimer);
|
||||
on<ToggleScheduleEvent>(_handleToggleTimer);
|
||||
on<ApiCountdownValueEvent>(_handleApiCountdownValue);
|
||||
}
|
||||
bool timerActive = false;
|
||||
int scheduledHours = 0;
|
||||
int scheduledMinutes = 0;
|
||||
|
||||
FutureOr<void> _onFetchAcStatus(
|
||||
AcFetchDeviceStatusEvent event, Emitter<AcsState> emit) async {
|
||||
@ -30,8 +40,23 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
|
||||
if (deviceStatus.countdown1 != 0) {
|
||||
// Convert API value to minutes
|
||||
final totalMinutes = deviceStatus.countdown1 * 6;
|
||||
scheduledHours = totalMinutes ~/ 60;
|
||||
scheduledMinutes = totalMinutes % 60;
|
||||
timerActive = true;
|
||||
_startCountdownTimer(emit);
|
||||
}
|
||||
|
||||
emit(ACStatusLoaded(
|
||||
status: deviceStatus,
|
||||
scheduledHours: scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes,
|
||||
isTimerActive: timerActive,
|
||||
));
|
||||
|
||||
_listenToChanges(event.deviceId);
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
@ -70,31 +95,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
|
||||
void _onAcStatusUpdated(AcStatusUpdated event, Emitter<AcsState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
}
|
||||
|
||||
// Future<void> testFirebaseConnection() async {
|
||||
// // Reference to a test node in your database
|
||||
// final testRef = FirebaseDatabase.instance.ref("test");
|
||||
|
||||
// // Write a test value
|
||||
// await testRef.set("Hello, Firebase!");
|
||||
|
||||
// // Listen for changes on the test node
|
||||
// testRef.onValue.listen((DatabaseEvent event) {
|
||||
// final data = event.snapshot.value;
|
||||
// print("Data from Firebase: $data");
|
||||
// // If you see "Hello, Firebase!" printed in your console, it means the connection works.
|
||||
// });
|
||||
// }
|
||||
|
||||
FutureOr<void> _onAcControl(
|
||||
AcControlEvent event, Emitter<AcsState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
|
||||
_updateLocalValue(event.code, event.value, emit);
|
||||
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
|
||||
await _runDebounce(
|
||||
isBatch: false,
|
||||
@ -151,7 +161,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
void _revertValueAndEmit(
|
||||
String deviceId, String code, dynamic oldValue, Emitter<AcsState> emit) {
|
||||
_updateLocalValue(code, oldValue, emit);
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
}
|
||||
|
||||
void _updateLocalValue(String code, dynamic value, Emitter<AcsState> emit) {
|
||||
@ -184,11 +194,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
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(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
}
|
||||
|
||||
dynamic _getValueByCode(String code) {
|
||||
@ -203,6 +218,8 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
return deviceStatus.fanSpeedsString;
|
||||
case 'child_lock':
|
||||
return deviceStatus.childLock;
|
||||
case 'countdown_time':
|
||||
return deviceStatus.countdown1;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -216,7 +233,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||
deviceStatus =
|
||||
AcStatusModel.fromJson(event.devicesIds.first, status.status);
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
} catch (e) {
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
@ -228,7 +245,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
|
||||
_updateLocalValue(event.code, event.value, emit);
|
||||
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
|
||||
await _runDebounce(
|
||||
isBatch: true,
|
||||
@ -257,4 +274,136 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _onClose(OnClose event, Emitter<AcsState> emit) {
|
||||
_countdownTimer?.cancel();
|
||||
_timer?.cancel();
|
||||
}
|
||||
|
||||
void _handleIncreaseTime(IncreaseTimeEvent event, Emitter<AcsState> emit) {
|
||||
if (state is! ACStatusLoaded) return;
|
||||
final currentState = state as ACStatusLoaded;
|
||||
int newHours = scheduledHours;
|
||||
int newMinutes = scheduledMinutes + 30;
|
||||
newHours += newMinutes ~/ 60;
|
||||
newMinutes = newMinutes % 60;
|
||||
if (newHours > 23) {
|
||||
newHours = 23;
|
||||
newMinutes = 59;
|
||||
}
|
||||
scheduledHours = newHours;
|
||||
scheduledMinutes = newMinutes;
|
||||
|
||||
emit(currentState.copyWith(
|
||||
scheduledHours: scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes,
|
||||
));
|
||||
}
|
||||
|
||||
void _handleDecreaseTime(DecreaseTimeEvent event, Emitter<AcsState> emit) {
|
||||
if (state is! ACStatusLoaded) return;
|
||||
final currentState = state as ACStatusLoaded;
|
||||
int totalMinutes = (scheduledHours * 60) + scheduledMinutes;
|
||||
totalMinutes = (totalMinutes - 30).clamp(0, 1440);
|
||||
scheduledHours = totalMinutes ~/ 60;
|
||||
scheduledMinutes = totalMinutes % 60;
|
||||
|
||||
emit(currentState.copyWith(
|
||||
scheduledHours: scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes,
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _handleToggleTimer(
|
||||
ToggleScheduleEvent event, Emitter<AcsState> emit) async {
|
||||
if (state is! ACStatusLoaded) return;
|
||||
final currentState = state as ACStatusLoaded;
|
||||
|
||||
timerActive = !timerActive;
|
||||
|
||||
if (timerActive) {
|
||||
final totalMinutes = scheduledHours * 60 + scheduledMinutes;
|
||||
if (totalMinutes <= 0) {
|
||||
timerActive = false;
|
||||
emit(currentState.copyWith(isTimerActive: timerActive));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final scaledValue = totalMinutes ~/ 6;
|
||||
await DevicesManagementApi().deviceControl(
|
||||
deviceId,
|
||||
Status(code: 'countdown_time', value: scaledValue),
|
||||
);
|
||||
_startCountdownTimer(emit);
|
||||
emit(currentState.copyWith(isTimerActive: timerActive));
|
||||
} catch (e) {
|
||||
timerActive = false;
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
} else {
|
||||
await DevicesManagementApi().deviceControl(
|
||||
deviceId,
|
||||
Status(code: 'countdown_time', value: 0),
|
||||
);
|
||||
_countdownTimer?.cancel();
|
||||
scheduledHours = 0;
|
||||
scheduledMinutes = 0;
|
||||
emit(currentState.copyWith(
|
||||
isTimerActive: timerActive,
|
||||
scheduledHours: 0,
|
||||
scheduledMinutes: 0,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _startCountdownTimer(Emitter<AcsState> emit) {
|
||||
_countdownTimer?.cancel();
|
||||
int totalSeconds = (scheduledHours * 3600) + (scheduledMinutes * 60);
|
||||
|
||||
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (totalSeconds > 0) {
|
||||
totalSeconds--;
|
||||
scheduledHours = totalSeconds ~/ 3600;
|
||||
scheduledMinutes = (totalSeconds % 3600) ~/ 60;
|
||||
add(UpdateTimerEvent());
|
||||
} else {
|
||||
_countdownTimer?.cancel();
|
||||
timerActive = false;
|
||||
scheduledHours = 0;
|
||||
scheduledMinutes = 0;
|
||||
add(TimerCompletedEvent());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _handleUpdateTimer(UpdateTimerEvent event, Emitter<AcsState> emit) {
|
||||
if (state is ACStatusLoaded) {
|
||||
final currentState = state as ACStatusLoaded;
|
||||
emit(currentState.copyWith(
|
||||
scheduledHours: scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes,
|
||||
isTimerActive: timerActive,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _handleApiCountdownValue(
|
||||
ApiCountdownValueEvent event, Emitter<AcsState> emit) {
|
||||
if (state is ACStatusLoaded) {
|
||||
final totalMinutes = event.apiValue * 6;
|
||||
final scheduledHours = totalMinutes ~/ 60;
|
||||
scheduledMinutes = totalMinutes % 60;
|
||||
_startCountdownTimer(
|
||||
emit,
|
||||
);
|
||||
add(UpdateTimerEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
add(OnClose());
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user