push countdown logic

This commit is contained in:
ashrafzarkanisala
2024-09-20 00:41:59 +03:00
parent facdef4741
commit 26816b99cd
6 changed files with 381 additions and 211 deletions

View File

@ -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();
} }
} }

View File

@ -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();
// }

View File

@ -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];
}

View File

@ -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,
];
} }

View File

@ -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(

View File

@ -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,
), ),
); );