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