mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
push countdown logic
This commit is contained in:
@ -1,3 +1,5 @@
|
|||||||
|
// water_heater_bloc.dart
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
@ -14,143 +16,147 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
on<ToggleWaterHeaterEvent>(_controlWaterHeater);
|
on<ToggleWaterHeaterEvent>(_controlWaterHeater);
|
||||||
on<UpdateScheduleEvent>(_updateScheduleEvent);
|
on<UpdateScheduleEvent>(_updateScheduleEvent);
|
||||||
on<StopScheduleEvent>(_stopScheduleEvent);
|
on<StopScheduleEvent>(_stopScheduleEvent);
|
||||||
|
on<DecrementCountdownEvent>(_onDecrementCountdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
late WaterHeaterStatusModel deviceStatus;
|
late WaterHeaterStatusModel deviceStatus;
|
||||||
Timer? _timer;
|
Timer? _countdownTimer;
|
||||||
|
|
||||||
FutureOr<void> _updateScheduleEvent(
|
FutureOr<void> _updateScheduleEvent(
|
||||||
UpdateScheduleEvent event,
|
UpdateScheduleEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) async {
|
) async {
|
||||||
final currentState = state as WaterHeaterScheduleViewState;
|
final currentState = state;
|
||||||
|
if (currentState is WaterHeaterDeviceStatusLoaded) {
|
||||||
|
final countdownRemaining =
|
||||||
|
// currentState.isActive == true
|
||||||
|
// ? currentState.countdownRemaining
|
||||||
|
// :
|
||||||
|
Duration(hours: event.hours, minutes: event.minutes);
|
||||||
|
|
||||||
final countdownRemaining = currentState.isActive
|
emit(currentState.copyWith(
|
||||||
? currentState.countdownRemaining
|
scheduleMode: event.scheduleMode,
|
||||||
: Duration(hours: event.hours, minutes: event.minutes);
|
hours: countdownRemaining.inHours,
|
||||||
|
minutes: countdownRemaining.inMinutes % 60,
|
||||||
|
isActive: currentState.isActive,
|
||||||
|
countdownRemaining: countdownRemaining,
|
||||||
|
));
|
||||||
|
|
||||||
emit(WaterHeaterScheduleViewState(
|
if (!currentState.isActive! && countdownRemaining > Duration.zero) {
|
||||||
scheduleMode: event.scheduleMode,
|
_startCountdown(emit, countdownRemaining);
|
||||||
hours: countdownRemaining!.inHours,
|
}
|
||||||
minutes: countdownRemaining.inMinutes % 60,
|
|
||||||
isActive: currentState.isActive,
|
|
||||||
countdownRemaining: countdownRemaining,
|
|
||||||
));
|
|
||||||
|
|
||||||
if (currentState.isActive) {
|
|
||||||
_startCountdown(countdownRemaining, emit);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _controlWaterHeater(
|
FutureOr<void> _controlWaterHeater(
|
||||||
ToggleWaterHeaterEvent event, Emitter<WaterHeaterState> emit) async {
|
ToggleWaterHeaterEvent event,
|
||||||
final oldValue = _getValueByCode(event.code);
|
Emitter<WaterHeaterState> emit,
|
||||||
|
) async {
|
||||||
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value, emit);
|
final oldValue = _getValueByCode(event.code);
|
||||||
|
|
||||||
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
_updateLocalValue(event.code, event.value);
|
||||||
|
|
||||||
final success = await _runDebounce(
|
emit(currentState.copyWith(
|
||||||
deviceId: event.deviceId,
|
status: deviceStatus,
|
||||||
code: event.code,
|
|
||||||
value: event.value,
|
|
||||||
oldValue: oldValue,
|
|
||||||
emit: emit,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (success && (event.code == "countdown_1" || event.code == "switch_inching")) {
|
|
||||||
final countdownDuration = Duration(seconds: event.value);
|
|
||||||
|
|
||||||
emit(WaterHeaterScheduleViewState(
|
|
||||||
scheduleMode: deviceStatus.scheduleMode,
|
|
||||||
hours: countdownDuration.inHours,
|
|
||||||
minutes: (countdownDuration.inMinutes % 60),
|
|
||||||
isActive: true,
|
|
||||||
countdownRemaining: countdownDuration,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
_startCountdown(countdownDuration, emit);
|
final success = await _runDebounce(
|
||||||
|
deviceId: event.deviceId,
|
||||||
|
code: event.code,
|
||||||
|
value: event.value,
|
||||||
|
oldValue: oldValue,
|
||||||
|
emit: emit,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (success &&
|
||||||
|
(event.code == "countdown_1" || event.code == "switch_inching")) {
|
||||||
|
final countdownDuration = Duration(seconds: event.value);
|
||||||
|
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
status: deviceStatus,
|
||||||
|
scheduleMode: deviceStatus.scheduleMode,
|
||||||
|
hours: countdownDuration.inHours,
|
||||||
|
minutes: (countdownDuration.inMinutes % 60),
|
||||||
|
isActive: true,
|
||||||
|
countdownRemaining: countdownDuration,
|
||||||
|
));
|
||||||
|
if (countdownDuration.inSeconds > 0) {
|
||||||
|
_startCountdown(emit, countdownDuration);
|
||||||
|
} else {
|
||||||
|
_countdownTimer?.cancel();
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
hours: 0,
|
||||||
|
minutes: 0,
|
||||||
|
isActive: false,
|
||||||
|
countdownRemaining: Duration.zero,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _runDebounce({
|
FutureOr<void> _stopScheduleEvent(
|
||||||
required String deviceId,
|
StopScheduleEvent event,
|
||||||
required String code,
|
Emitter<WaterHeaterState> emit,
|
||||||
required dynamic value,
|
) async {
|
||||||
required dynamic oldValue,
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
required Emitter<WaterHeaterState> emit,
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
}) async {
|
|
||||||
final completer = Completer<bool>();
|
|
||||||
|
|
||||||
if (_timer != null) {
|
_countdownTimer?.cancel();
|
||||||
_timer!.cancel();
|
|
||||||
}
|
deviceStatus = deviceStatus.copyWith(
|
||||||
|
countdownHours: 0,
|
||||||
|
countdownMinutes: 0,
|
||||||
|
scheduleMode: ScheduleModes.countdown,
|
||||||
|
);
|
||||||
|
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
status: deviceStatus,
|
||||||
|
scheduleMode: ScheduleModes.countdown,
|
||||||
|
hours: 0,
|
||||||
|
minutes: 0,
|
||||||
|
isActive: false,
|
||||||
|
countdownRemaining: Duration.zero,
|
||||||
|
));
|
||||||
|
|
||||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().deviceControl(
|
final status = await DevicesManagementApi().deviceControl(
|
||||||
deviceId,
|
event.deviceId,
|
||||||
Status(code: code, value: value),
|
Status(code: 'countdown_1', value: 0),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
_revertValueAndEmit(deviceId, code, oldValue, emit);
|
emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.'));
|
||||||
completer.complete(false);
|
|
||||||
} else {
|
|
||||||
completer.complete(true);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_revertValueAndEmit(deviceId, code, oldValue, emit);
|
emit(WaterHeaterFailedState(error: e.toString()));
|
||||||
completer.complete(false);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return completer.future;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValueAndEmit(
|
|
||||||
String deviceId, String code, dynamic oldValue, Emitter<WaterHeaterState> emit) {
|
|
||||||
_updateLocalValue(code, oldValue, emit);
|
|
||||||
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateLocalValue(String code, dynamic value, Emitter<WaterHeaterState> emit) {
|
|
||||||
switch (code) {
|
|
||||||
case 'switch_1':
|
|
||||||
if (value is bool) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(heaterSwitch: value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _getValueByCode(String code) {
|
|
||||||
switch (code) {
|
|
||||||
case 'switch_1':
|
|
||||||
return deviceStatus.heaterSwitch;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _fetchWaterHeaterStatus(
|
FutureOr<void> _fetchWaterHeaterStatus(
|
||||||
WaterHeaterFetchStatusEvent event, Emitter<WaterHeaterState> emit) async {
|
WaterHeaterFetchStatusEvent event,
|
||||||
|
Emitter<WaterHeaterState> emit,
|
||||||
|
) async {
|
||||||
emit(WaterHeaterLoadingState());
|
emit(WaterHeaterLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
final status =
|
||||||
deviceStatus = WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
|
deviceStatus =
|
||||||
|
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
|
||||||
if (deviceStatus.countdownHours > 0 || deviceStatus.countdownMinutes > 0) {
|
if (deviceStatus.countdownHours > 0 ||
|
||||||
|
deviceStatus.countdownMinutes > 0) {
|
||||||
final remainingDuration = Duration(
|
final remainingDuration = Duration(
|
||||||
hours: deviceStatus.countdownHours,
|
hours: deviceStatus.countdownHours,
|
||||||
minutes: deviceStatus.countdownMinutes,
|
minutes: deviceStatus.countdownMinutes,
|
||||||
);
|
);
|
||||||
|
|
||||||
emit(WaterHeaterScheduleViewState(
|
emit(WaterHeaterDeviceStatusLoaded(
|
||||||
|
deviceStatus,
|
||||||
scheduleMode: deviceStatus.scheduleMode,
|
scheduleMode: deviceStatus.scheduleMode,
|
||||||
hours: deviceStatus.countdownHours,
|
hours: deviceStatus.countdownHours,
|
||||||
minutes: deviceStatus.countdownMinutes,
|
minutes: deviceStatus.countdownMinutes,
|
||||||
@ -158,9 +164,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
countdownRemaining: remainingDuration,
|
countdownRemaining: remainingDuration,
|
||||||
));
|
));
|
||||||
|
|
||||||
// _startCountdown(remainingDuration, emit);
|
_startCountdown(emit, remainingDuration);
|
||||||
} else {
|
} else {
|
||||||
emit(WaterHeaterScheduleViewState(
|
emit(WaterHeaterDeviceStatusLoaded(
|
||||||
|
deviceStatus,
|
||||||
scheduleMode: deviceStatus.scheduleMode,
|
scheduleMode: deviceStatus.scheduleMode,
|
||||||
hours: 0,
|
hours: 0,
|
||||||
minutes: 0,
|
minutes: 0,
|
||||||
@ -172,55 +179,124 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _startCountdown(Duration duration, Emitter<WaterHeaterState> emit) {
|
_onDecrementCountdown(
|
||||||
_timer?.cancel();
|
DecrementCountdownEvent event,
|
||||||
|
Emitter<WaterHeaterState> emit,
|
||||||
|
) {
|
||||||
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
|
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||||
|
|
||||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
if (currentState.countdownRemaining != null &&
|
||||||
final state = this.state as WaterHeaterScheduleViewState;
|
currentState.countdownRemaining! > Duration.zero) {
|
||||||
final remaining = state.countdownRemaining! - const Duration(seconds: 1);
|
final newRemaining =
|
||||||
|
currentState.countdownRemaining! - const Duration(minutes: 1);
|
||||||
|
|
||||||
if (remaining.isNegative || remaining == Duration.zero) {
|
if (newRemaining <= Duration.zero) {
|
||||||
_timer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
emit(WaterHeaterScheduleViewState(
|
emit(currentState.copyWith(
|
||||||
scheduleMode: state.scheduleMode,
|
hours: 0,
|
||||||
hours: 0,
|
minutes: 0,
|
||||||
minutes: 0,
|
isActive: false,
|
||||||
isActive: false,
|
countdownRemaining: Duration.zero,
|
||||||
countdownRemaining: Duration.zero,
|
));
|
||||||
));
|
return;
|
||||||
} else {
|
}
|
||||||
emit(WaterHeaterScheduleViewState(
|
|
||||||
scheduleMode: state.scheduleMode,
|
int totalSeconds = newRemaining.inSeconds;
|
||||||
hours: remaining.inHours,
|
|
||||||
minutes: remaining.inMinutes % 60,
|
int newHours = totalSeconds ~/ 3600;
|
||||||
isActive: true,
|
int newMinutes = (totalSeconds % 3600) ~/ 60;
|
||||||
countdownRemaining: remaining,
|
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
hours: newHours,
|
||||||
|
minutes: newMinutes,
|
||||||
|
countdownRemaining: newRemaining,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startCountdown(
|
||||||
|
Emitter<WaterHeaterState> emit, Duration countdownRemaining) {
|
||||||
|
_countdownTimer?.cancel();
|
||||||
|
|
||||||
|
_countdownTimer = Timer.periodic(const Duration(minutes: 1), (timer) {
|
||||||
|
add(DecrementCountdownEvent());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _stopScheduleEvent(
|
Future<bool> _runDebounce({
|
||||||
StopScheduleEvent event,
|
required String deviceId,
|
||||||
Emitter<WaterHeaterState> emit,
|
required String code,
|
||||||
) {
|
required dynamic value,
|
||||||
_timer?.cancel();
|
required dynamic oldValue,
|
||||||
deviceStatus = deviceStatus.copyWith(
|
required Emitter<WaterHeaterState> emit,
|
||||||
countdownHours: 0,
|
}) async {
|
||||||
countdownMinutes: 0,
|
try {
|
||||||
scheduleMode: ScheduleModes.countdown,
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
);
|
|
||||||
emit(const WaterHeaterScheduleViewState(
|
final status = await DevicesManagementApi().deviceControl(
|
||||||
scheduleMode: ScheduleModes.countdown,
|
deviceId,
|
||||||
hours: 0,
|
Status(code: code, value: value),
|
||||||
minutes: 0,
|
);
|
||||||
isActive: false,
|
|
||||||
));
|
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,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateLocalValue(String code, dynamic value) {
|
||||||
|
switch (code) {
|
||||||
|
case 'switch_1':
|
||||||
|
if (value is bool) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(heaterSwitch: value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'countdown_1':
|
||||||
|
if (value is int) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(
|
||||||
|
countdownHours: value ~/ 60,
|
||||||
|
countdownMinutes: value % 60,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic _getValueByCode(String code) {
|
||||||
|
switch (code) {
|
||||||
|
case 'switch_1':
|
||||||
|
return deviceStatus.heaterSwitch;
|
||||||
|
case 'countdown_1':
|
||||||
|
return deviceStatus.countdownHours * 60 + deviceStatus.countdownMinutes;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() {
|
Future<void> close() {
|
||||||
_timer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
part of 'water_heater_bloc.dart';
|
part of 'water_heater_bloc.dart';
|
||||||
|
|
||||||
sealed class WaterHeaterEvent extends Equatable {
|
sealed class WaterHeaterEvent extends Equatable {
|
||||||
@ -12,11 +13,14 @@ final class ToggleWaterHeaterEvent extends WaterHeaterEvent {
|
|||||||
final String deviceId;
|
final String deviceId;
|
||||||
final String code;
|
final String code;
|
||||||
|
|
||||||
const ToggleWaterHeaterEvent(
|
const ToggleWaterHeaterEvent({
|
||||||
{required this.value, required this.deviceId, required this.code});
|
required this.value,
|
||||||
|
required this.deviceId,
|
||||||
|
required this.code,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [value];
|
List<Object?> get props => [value, deviceId, code];
|
||||||
}
|
}
|
||||||
|
|
||||||
final class UpdateScheduleEvent extends WaterHeaterEvent {
|
final class UpdateScheduleEvent extends WaterHeaterEvent {
|
||||||
@ -24,16 +28,23 @@ final class UpdateScheduleEvent extends WaterHeaterEvent {
|
|||||||
final int hours;
|
final int hours;
|
||||||
final int minutes;
|
final int minutes;
|
||||||
|
|
||||||
const UpdateScheduleEvent(
|
const UpdateScheduleEvent({
|
||||||
{required this.scheduleMode, required this.hours, required this.minutes});
|
required this.scheduleMode,
|
||||||
|
required this.hours,
|
||||||
|
required this.minutes,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [scheduleMode, hours, minutes];
|
List<Object?> get props => [scheduleMode, hours, minutes];
|
||||||
}
|
}
|
||||||
|
|
||||||
final class StopScheduleEvent extends WaterHeaterEvent {}
|
final class StopScheduleEvent extends WaterHeaterEvent {
|
||||||
|
final String deviceId;
|
||||||
|
|
||||||
class WaterHeaterFetchStatusEvent extends WaterHeaterEvent {
|
const StopScheduleEvent(this.deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
final class WaterHeaterFetchStatusEvent extends WaterHeaterEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
|
||||||
const WaterHeaterFetchStatusEvent(this.deviceId);
|
const WaterHeaterFetchStatusEvent(this.deviceId);
|
||||||
@ -42,7 +53,7 @@ class WaterHeaterFetchStatusEvent extends WaterHeaterEvent {
|
|||||||
List<Object?> get props => [deviceId];
|
List<Object?> get props => [deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
class WaterHeaterFetchBatchStatusEvent extends WaterHeaterEvent {
|
final class WaterHeaterFetchBatchStatusEvent extends WaterHeaterEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
|
||||||
const WaterHeaterFetchBatchStatusEvent(this.deviceId);
|
const WaterHeaterFetchBatchStatusEvent(this.deviceId);
|
||||||
@ -51,6 +62,4 @@ class WaterHeaterFetchBatchStatusEvent extends WaterHeaterEvent {
|
|||||||
List<Object?> get props => [deviceId];
|
List<Object?> get props => [deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
// class ShowScheduleViewEvent extends WaterHeaterEvent {
|
final class DecrementCountdownEvent extends WaterHeaterEvent {}
|
||||||
// const ShowScheduleViewEvent();
|
|
||||||
// }
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
part of 'water_heater_bloc.dart';
|
// water_heater_state.dart
|
||||||
|
|
||||||
enum ScheduleType { countdown, schedule, circulate, inching }
|
part of 'water_heater_bloc.dart';
|
||||||
|
|
||||||
sealed class WaterHeaterState extends Equatable {
|
sealed class WaterHeaterState extends Equatable {
|
||||||
const WaterHeaterState();
|
const WaterHeaterState();
|
||||||
@ -15,11 +15,43 @@ final class WaterHeaterLoadingState extends WaterHeaterState {}
|
|||||||
|
|
||||||
final class WaterHeaterDeviceStatusLoaded extends WaterHeaterState {
|
final class WaterHeaterDeviceStatusLoaded extends WaterHeaterState {
|
||||||
final WaterHeaterStatusModel status;
|
final WaterHeaterStatusModel status;
|
||||||
|
final ScheduleModes? scheduleMode;
|
||||||
|
final int? hours;
|
||||||
|
final int? minutes;
|
||||||
|
final bool? isActive;
|
||||||
|
final Duration? countdownRemaining;
|
||||||
|
|
||||||
const WaterHeaterDeviceStatusLoaded(this.status);
|
const WaterHeaterDeviceStatusLoaded(
|
||||||
|
this.status, {
|
||||||
|
this.scheduleMode,
|
||||||
|
this.hours,
|
||||||
|
this.minutes,
|
||||||
|
this.isActive,
|
||||||
|
this.countdownRemaining,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [status];
|
List<Object?> get props =>
|
||||||
|
[status, scheduleMode, hours, minutes, isActive, countdownRemaining];
|
||||||
|
|
||||||
|
/// Creates a new instance with updated fields.
|
||||||
|
WaterHeaterDeviceStatusLoaded copyWith({
|
||||||
|
WaterHeaterStatusModel? status,
|
||||||
|
ScheduleModes? scheduleMode,
|
||||||
|
int? hours,
|
||||||
|
int? minutes,
|
||||||
|
bool? isActive,
|
||||||
|
Duration? countdownRemaining,
|
||||||
|
}) {
|
||||||
|
return WaterHeaterDeviceStatusLoaded(
|
||||||
|
status ?? this.status,
|
||||||
|
scheduleMode: scheduleMode ?? this.scheduleMode,
|
||||||
|
hours: hours ?? this.hours,
|
||||||
|
minutes: minutes ?? this.minutes,
|
||||||
|
isActive: isActive ?? this.isActive,
|
||||||
|
countdownRemaining: countdownRemaining ?? this.countdownRemaining,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class WaterHeaterFailedState extends WaterHeaterState {
|
final class WaterHeaterFailedState extends WaterHeaterState {
|
||||||
@ -39,23 +71,3 @@ final class WaterHeaterBatchFailedState extends WaterHeaterState {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [error];
|
List<Object?> get props => [error];
|
||||||
}
|
}
|
||||||
|
|
||||||
class WaterHeaterScheduleViewState extends WaterHeaterState {
|
|
||||||
final ScheduleModes scheduleMode;
|
|
||||||
final int hours;
|
|
||||||
final int minutes;
|
|
||||||
final bool isActive;
|
|
||||||
final Duration? countdownRemaining;
|
|
||||||
|
|
||||||
const WaterHeaterScheduleViewState({
|
|
||||||
required this.scheduleMode,
|
|
||||||
required this.hours,
|
|
||||||
required this.minutes,
|
|
||||||
required this.isActive,
|
|
||||||
this.countdownRemaining,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props =>
|
|
||||||
[scheduleMode, hours, minutes, isActive, countdownRemaining];
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
import 'package:equatable/equatable.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';
|
||||||
|
|
||||||
enum ScheduleModes { countdown, schedule, circulate, inching }
|
enum ScheduleModes { countdown, schedule, circulate, inching }
|
||||||
|
|
||||||
class WaterHeaterStatusModel {
|
class WaterHeaterStatusModel extends Equatable {
|
||||||
final String uuid;
|
final String uuid;
|
||||||
final bool heaterSwitch;
|
final bool heaterSwitch;
|
||||||
final int countdownHours;
|
final int countdownHours;
|
||||||
@ -34,7 +35,7 @@ class WaterHeaterStatusModel {
|
|||||||
heaterSwitch = status.value ?? false;
|
heaterSwitch = status.value ?? false;
|
||||||
break;
|
break;
|
||||||
case 'countdown_1':
|
case 'countdown_1':
|
||||||
countdownInSeconds = status.value ?? 0;
|
countdownInSeconds = status.value ?? 0;
|
||||||
break;
|
break;
|
||||||
case 'relay_status':
|
case 'relay_status':
|
||||||
relayStatus = status.value ?? 'memory';
|
relayStatus = status.value ?? 'memory';
|
||||||
@ -48,9 +49,8 @@ class WaterHeaterStatusModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final countdownHours = countdownInSeconds ~/ 3600;
|
final countdownHours = countdownInSeconds ~/ 3600;
|
||||||
final countdownMinutes =
|
final countdownMinutes = (countdownInSeconds % 3600) ~/ 60;
|
||||||
(countdownInSeconds % 3600) ~/ 60;
|
|
||||||
|
|
||||||
return WaterHeaterStatusModel(
|
return WaterHeaterStatusModel(
|
||||||
uuid: id,
|
uuid: id,
|
||||||
@ -97,4 +97,15 @@ class WaterHeaterStatusModel {
|
|||||||
return ScheduleModes.countdown;
|
return ScheduleModes.countdown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
uuid,
|
||||||
|
heaterSwitch,
|
||||||
|
countdownHours,
|
||||||
|
countdownMinutes,
|
||||||
|
scheduleMode,
|
||||||
|
relayStatus,
|
||||||
|
cycleTiming,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,12 @@ class WaterHeaterDeviceControl extends StatelessWidget
|
|||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (state is WaterHeaterDeviceStatusLoaded) {
|
} else if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
return _buildStatusControls(context, state.status);
|
return _buildStatusControls(context, state.status);
|
||||||
} else if (state is WaterHeaterScheduleViewState) {
|
}
|
||||||
final status = context.read<WaterHeaterBloc>().deviceStatus;
|
// else if (state is WaterHeaterScheduleViewState) {
|
||||||
return _buildStatusControls(context, status);
|
// final status = context.read<WaterHeaterBloc>().deviceStatus;
|
||||||
} else if (state is WaterHeaterFailedState ||
|
// return _buildStatusControls(context, status);
|
||||||
|
// }
|
||||||
|
else if (state is WaterHeaterFailedState ||
|
||||||
state is WaterHeaterBatchFailedState) {
|
state is WaterHeaterBatchFailedState) {
|
||||||
return const Center(child: Text('Error fetching status'));
|
return const Center(child: Text('Error fetching status'));
|
||||||
} else {
|
} else {
|
||||||
@ -75,7 +77,6 @@ class WaterHeaterDeviceControl extends StatelessWidget
|
|||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// context.read<WaterHeaterBloc>().add(const ShowScheduleViewEvent());
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => BlocProvider.value(
|
builder: (ctx) => BlocProvider.value(
|
||||||
|
@ -7,11 +7,63 @@ import 'package:syncrow_web/pages/device_managment/water_heater/models/water_hea
|
|||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
class BuildScheduleView extends StatelessWidget {
|
class BuildScheduleView extends StatefulWidget {
|
||||||
const BuildScheduleView({super.key, required this.status});
|
const BuildScheduleView({super.key, required this.status});
|
||||||
|
|
||||||
final WaterHeaterStatusModel status;
|
final WaterHeaterStatusModel status;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_BuildScheduleViewState createState() => _BuildScheduleViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BuildScheduleViewState extends State<BuildScheduleView> {
|
||||||
|
// late FixedExtentScrollController hoursController;
|
||||||
|
// late FixedExtentScrollController minutesController;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void initState() {
|
||||||
|
// super.initState();
|
||||||
|
// _initializeControllers();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void didUpdateWidget(covariant BuildScheduleView oldWidget) {
|
||||||
|
// super.didUpdateWidget(oldWidget);
|
||||||
|
// final state = context.read<WaterHeaterBloc>().state;
|
||||||
|
// if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
|
// _initializeControllers();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void _initializeControllers() {
|
||||||
|
// final state = context.read<WaterHeaterBloc>().state;
|
||||||
|
// if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
|
// hoursController =
|
||||||
|
// FixedExtentScrollController(initialItem: state.hours ?? 0);
|
||||||
|
// minutesController =
|
||||||
|
// FixedExtentScrollController(initialItem: state.minutes ?? 0);
|
||||||
|
// } else {
|
||||||
|
// hoursController = FixedExtentScrollController(initialItem: 0);
|
||||||
|
// minutesController = FixedExtentScrollController(initialItem: 0);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void _updateControllers(int hours, int minutes) {
|
||||||
|
// if (hoursController.hasClients) {
|
||||||
|
// hoursController.jumpToItem(hours);
|
||||||
|
// }
|
||||||
|
// if (minutesController.hasClients) {
|
||||||
|
// minutesController.jumpToItem(minutes);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void dispose() {
|
||||||
|
// hoursController.dispose();
|
||||||
|
// minutesController.dispose();
|
||||||
|
// super.dispose();
|
||||||
|
// }
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Dialog(
|
return Dialog(
|
||||||
@ -27,7 +79,8 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20),
|
||||||
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is WaterHeaterScheduleViewState) {
|
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
|
//_updateControllers(state.hours ?? 0, state.minutes ?? 0);
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -75,9 +128,7 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
color: ColorsManager.grayColor,
|
color: ColorsManager.grayColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(height: 4),
|
||||||
height: 4,
|
|
||||||
),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
@ -101,8 +152,8 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
.read<WaterHeaterBloc>()
|
.read<WaterHeaterBloc>()
|
||||||
.add(UpdateScheduleEvent(
|
.add(UpdateScheduleEvent(
|
||||||
scheduleMode: value,
|
scheduleMode: value,
|
||||||
hours: state.hours,
|
hours: state.hours ?? 0,
|
||||||
minutes: state.minutes,
|
minutes: state.minutes ?? 0,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -128,8 +179,8 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
.read<WaterHeaterBloc>()
|
.read<WaterHeaterBloc>()
|
||||||
.add(UpdateScheduleEvent(
|
.add(UpdateScheduleEvent(
|
||||||
scheduleMode: value,
|
scheduleMode: value,
|
||||||
hours: state.hours,
|
hours: state.hours ?? 0,
|
||||||
minutes: state.minutes,
|
minutes: state.minutes ?? 0,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -154,8 +205,8 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
.read<WaterHeaterBloc>()
|
.read<WaterHeaterBloc>()
|
||||||
.add(UpdateScheduleEvent(
|
.add(UpdateScheduleEvent(
|
||||||
scheduleMode: value,
|
scheduleMode: value,
|
||||||
hours: state.hours,
|
hours: state.hours ?? 0,
|
||||||
minutes: state.minutes,
|
minutes: state.minutes ?? 0,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -180,8 +231,8 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
.read<WaterHeaterBloc>()
|
.read<WaterHeaterBloc>()
|
||||||
.add(UpdateScheduleEvent(
|
.add(UpdateScheduleEvent(
|
||||||
scheduleMode: value,
|
scheduleMode: value,
|
||||||
hours: state.hours,
|
hours: state.hours ?? 0,
|
||||||
minutes: state.minutes,
|
minutes: state.minutes ?? 0,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -230,7 +281,7 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: (state.countdownRemaining != null &&
|
child: (state.countdownRemaining != null &&
|
||||||
state.isActive)
|
state.isActive == true)
|
||||||
? DefaultButton(
|
? DefaultButton(
|
||||||
height: 40,
|
height: 40,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -242,12 +293,13 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
ScheduleModes.inching) {
|
ScheduleModes.inching) {
|
||||||
code = 'switch_inching';
|
code = 'switch_inching';
|
||||||
}
|
}
|
||||||
context
|
context.read<WaterHeaterBloc>().add(
|
||||||
.read<WaterHeaterBloc>()
|
StopScheduleEvent(
|
||||||
.add(StopScheduleEvent());
|
widget.status.uuid));
|
||||||
context.read<WaterHeaterBloc>().add(
|
context.read<WaterHeaterBloc>().add(
|
||||||
ToggleWaterHeaterEvent(
|
ToggleWaterHeaterEvent(
|
||||||
deviceId: status.uuid,
|
deviceId:
|
||||||
|
widget.status.uuid,
|
||||||
code: code,
|
code: code,
|
||||||
value: 0,
|
value: 0,
|
||||||
),
|
),
|
||||||
@ -269,13 +321,16 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
context.read<WaterHeaterBloc>().add(
|
context.read<WaterHeaterBloc>().add(
|
||||||
ToggleWaterHeaterEvent(
|
ToggleWaterHeaterEvent(
|
||||||
deviceId: status.uuid,
|
deviceId:
|
||||||
|
widget.status.uuid,
|
||||||
code: code,
|
code: code,
|
||||||
// value is time in seconds
|
|
||||||
value: Duration(
|
value: Duration(
|
||||||
hours: state.hours,
|
hours:
|
||||||
|
state.hours ??
|
||||||
|
0,
|
||||||
minutes:
|
minutes:
|
||||||
state.minutes)
|
state.minutes ??
|
||||||
|
0)
|
||||||
.inSeconds,
|
.inSeconds,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -303,7 +358,7 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Row _hourMinutesWheel(
|
Row _hourMinutesWheel(
|
||||||
WaterHeaterScheduleViewState state, BuildContext context) {
|
WaterHeaterDeviceStatusLoaded state, BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -320,16 +375,19 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: ListWheelScrollView.useDelegate(
|
child: ListWheelScrollView.useDelegate(
|
||||||
controller:
|
key: ValueKey('hours_${state.hours}'),
|
||||||
FixedExtentScrollController(initialItem: state.hours),
|
controller: FixedExtentScrollController(
|
||||||
|
initialItem: state.hours ?? 0,
|
||||||
|
),
|
||||||
itemExtent: 40.0,
|
itemExtent: 40.0,
|
||||||
physics: FixedExtentScrollPhysics(),
|
physics: const FixedExtentScrollPhysics(),
|
||||||
onSelectedItemChanged: (int value) {
|
onSelectedItemChanged: (int value) {
|
||||||
context.read<WaterHeaterBloc>().add(
|
context.read<WaterHeaterBloc>().add(
|
||||||
UpdateScheduleEvent(
|
UpdateScheduleEvent(
|
||||||
scheduleMode: state.scheduleMode,
|
scheduleMode:
|
||||||
|
state.scheduleMode ?? ScheduleModes.countdown,
|
||||||
hours: value,
|
hours: value,
|
||||||
minutes: state.minutes,
|
minutes: state.minutes ?? 0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -370,15 +428,18 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: ListWheelScrollView.useDelegate(
|
child: ListWheelScrollView.useDelegate(
|
||||||
controller:
|
key: ValueKey('minutes_${state.minutes}'),
|
||||||
FixedExtentScrollController(initialItem: state.minutes),
|
controller: FixedExtentScrollController(
|
||||||
|
initialItem: state.minutes ?? 0,
|
||||||
|
),
|
||||||
itemExtent: 40.0,
|
itemExtent: 40.0,
|
||||||
physics: FixedExtentScrollPhysics(),
|
physics: const FixedExtentScrollPhysics(),
|
||||||
onSelectedItemChanged: (int value) {
|
onSelectedItemChanged: (int value) {
|
||||||
context.read<WaterHeaterBloc>().add(
|
context.read<WaterHeaterBloc>().add(
|
||||||
UpdateScheduleEvent(
|
UpdateScheduleEvent(
|
||||||
scheduleMode: state.scheduleMode,
|
scheduleMode:
|
||||||
hours: state.hours,
|
state.scheduleMode ?? ScheduleModes.countdown,
|
||||||
|
hours: state.hours ?? 0,
|
||||||
minutes: value,
|
minutes: value,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user