diff --git a/lib/pages/device_managment/garage_door/bloc/garage_door_bloc.dart b/lib/pages/device_managment/garage_door/bloc/garage_door_bloc.dart index f640a50d..04af1e39 100644 --- a/lib/pages/device_managment/garage_door/bloc/garage_door_bloc.dart +++ b/lib/pages/device_managment/garage_door/bloc/garage_door_bloc.dart @@ -33,12 +33,16 @@ class GarageDoorBloc extends Bloc { on(_updateFunctionOn); on(_initializeAddSchedule); on(_backToGridView); + on(_onUpdateCountdownAlarm); + on(_onUpdateTrTimeCon); } - void _fetchGarageDoorStatus(GarageDoorInitialEvent event, Emitter emit) async { + void _fetchGarageDoorStatus( + GarageDoorInitialEvent event, Emitter emit) async { emit(GarageDoorLoadingState()); try { - var response = await DevicesManagementApi().getDeviceStatus(event.deviceId); + var response = + await DevicesManagementApi().getDeviceStatus(event.deviceId); deviceStatus = GarageDoorStatusModel.fromJson(deviceId, response.status); emit(GarageDoorLoadedState(status: deviceStatus)); } catch (e) { @@ -46,7 +50,8 @@ class GarageDoorBloc extends Bloc { } } - Future _addSchedule(AddGarageDoorScheduleEvent event, Emitter emit) async { + Future _addSchedule( + AddGarageDoorScheduleEvent event, Emitter emit) async { try { ScheduleEntry newSchedule = ScheduleEntry( category: event.category, @@ -54,9 +59,11 @@ class GarageDoorBloc extends Bloc { function: Status(code: 'switch_1', value: event.functionOn), days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays), ); - bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId); + bool success = + await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId); if (success) { - add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1')); + add(FetchGarageDoorSchedulesEvent( + deviceId: deviceId, category: 'switch_1')); } else { emit(GarageDoorLoadedState(status: deviceStatus)); } @@ -65,7 +72,29 @@ class GarageDoorBloc extends Bloc { } } - Future _updateSchedule(UpdateGarageDoorScheduleEvent event, Emitter emit) async { + void _onUpdateCountdownAlarm( + UpdateCountdownAlarmEvent event, Emitter emit) { + final currentState = state; + if (currentState is GarageDoorLoadedState) { + emit(currentState.copyWith( + status: + currentState.status.copyWith(countdownAlarm: event.countdownAlarm), + )); + } + } + + void _onUpdateTrTimeCon( + UpdateTrTimeConEvent event, Emitter emit) { + final currentState = state; + if (currentState is GarageDoorLoadedState) { + emit(currentState.copyWith( + status: currentState.status.copyWith(trTimeCon: event.trTimeCon), + )); + } + } + + Future _updateSchedule(UpdateGarageDoorScheduleEvent event, + Emitter emit) async { try { final updatedSchedules = deviceStatus.schedules?.map((schedule) { if (schedule.scheduleId == event.scheduleId) { @@ -92,12 +121,15 @@ class GarageDoorBloc extends Bloc { } } - Future _deleteSchedule(DeleteGarageDoorScheduleEvent event, Emitter emit) async { + Future _deleteSchedule(DeleteGarageDoorScheduleEvent event, + Emitter emit) async { try { - bool success = await DevicesManagementApi().deleteScheduleRecord(deviceStatus.uuid, event.scheduleId); + bool success = await DevicesManagementApi() + .deleteScheduleRecord(deviceStatus.uuid, event.scheduleId); if (success) { - final updatedSchedules = - deviceStatus.schedules?.where((schedule) => schedule.scheduleId != event.scheduleId).toList(); + final updatedSchedules = deviceStatus.schedules + ?.where((schedule) => schedule.scheduleId != event.scheduleId) + .toList(); deviceStatus = deviceStatus.copyWith(schedules: updatedSchedules); emit(GarageDoorLoadedState(status: deviceStatus)); } else { @@ -108,11 +140,12 @@ class GarageDoorBloc extends Bloc { } } - Future _fetchSchedules(FetchGarageDoorSchedulesEvent event, Emitter emit) async { + Future _fetchSchedules(FetchGarageDoorSchedulesEvent event, + Emitter emit) async { emit(ScheduleGarageLoadingState()); try { - List schedules = - await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category); + List schedules = await DevicesManagementApi() + .getDeviceSchedules(deviceStatus.uuid, event.category); deviceStatus = deviceStatus.copyWith(schedules: schedules); emit( GarageDoorLoadedState( @@ -130,30 +163,37 @@ class GarageDoorBloc extends Bloc { } } - Future _updateSelectedTime(UpdateSelectedTimeEvent event, Emitter emit) async { + Future _updateSelectedTime( + UpdateSelectedTimeEvent event, Emitter emit) async { final currentState = state; if (currentState is GarageDoorLoadedState) { emit(currentState.copyWith(selectedTime: event.selectedTime)); } } - Future _updateSelectedDay(UpdateSelectedDayEvent event, Emitter emit) async { + Future _updateSelectedDay( + UpdateSelectedDayEvent event, Emitter emit) async { final currentState = state; if (currentState is GarageDoorLoadedState) { List updatedDays = List.from(currentState.selectedDays); updatedDays[event.dayIndex] = event.isSelected; - emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime)); + emit(currentState.copyWith( + selectedDays: updatedDays, selectedTime: currentState.selectedTime)); } } - Future _updateFunctionOn(UpdateFunctionOnEvent event, Emitter emit) async { + Future _updateFunctionOn( + UpdateFunctionOnEvent event, Emitter emit) async { final currentState = state; if (currentState is GarageDoorLoadedState) { - emit(currentState.copyWith(functionOn: event.functionOn, selectedTime: currentState.selectedTime)); + emit(currentState.copyWith( + functionOn: event.functionOn, + selectedTime: currentState.selectedTime)); } } - Future _initializeAddSchedule(InitializeAddScheduleEvent event, Emitter emit) async { + Future _initializeAddSchedule( + InitializeAddScheduleEvent event, Emitter emit) async { final currentState = state; if (currentState is GarageDoorLoadedState) { emit(currentState.copyWith( @@ -165,24 +205,30 @@ class GarageDoorBloc extends Bloc { } } - Future _fetchRecords(FetchGarageDoorRecordsEvent event, Emitter emit) async { + Future _fetchRecords( + FetchGarageDoorRecordsEvent event, Emitter emit) async { emit(GarageDoorReportsLoadingState()); try { - final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch; + final from = DateTime.now() + .subtract(const Duration(days: 30)) + .millisecondsSinceEpoch; final to = DateTime.now().millisecondsSinceEpoch; final DeviceReport records = - await DevicesManagementApi.getDeviceReportsByDate(event.deviceId, 'switch_1', from.toString(), to.toString()); + await DevicesManagementApi.getDeviceReportsByDate( + event.deviceId, 'switch_1', from.toString(), to.toString()); emit(GarageDoorReportsState(deviceReport: records)); } catch (e) { emit(GarageDoorReportsFailedState(error: e.toString())); } } - void _backToGridView(BackToGarageDoorGridViewEvent event, Emitter emit) { + void _backToGridView( + BackToGarageDoorGridViewEvent event, Emitter emit) { emit(GarageDoorLoadedState(status: deviceStatus)); } - void _handleUpdate(GarageDoorUpdatedEvent event, Emitter emit) { + void _handleUpdate( + GarageDoorUpdatedEvent event, Emitter emit) { emit(GarageDoorLoadedState(status: deviceStatus)); } @@ -198,9 +244,11 @@ class GarageDoorBloc extends Bloc { late bool status; await Future.delayed(const Duration(milliseconds: 500)); if (isBatch) { - status = await DevicesManagementApi().deviceBatchControl(deviceId, code, value); + status = await DevicesManagementApi() + .deviceBatchControl(deviceId, code, value); } else { - status = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value)); + status = await DevicesManagementApi() + .deviceControl(deviceId, Status(code: code, value: value)); } if (!status) { @@ -215,34 +263,47 @@ class GarageDoorBloc extends Bloc { } } - void _increaseDelay(IncreaseGarageDoorDelayEvent event, Emitter emit) async { + void _increaseDelay( + IncreaseGarageDoorDelayEvent event, Emitter emit) async { // if (deviceStatus.countdown1 != 0) { try { - deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay + Duration(minutes: 10)); + deviceStatus = deviceStatus.copyWith( + delay: deviceStatus.delay + Duration(minutes: 10)); emit(GarageDoorLoadedState(status: deviceStatus)); - add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1')); + add(GarageDoorControlEvent( + deviceId: event.deviceId, + value: deviceStatus.delay.inSeconds, + code: 'countdown_1')); } catch (e) { emit(GarageDoorErrorState(message: e.toString())); } // } } - void _decreaseDelay(DecreaseGarageDoorDelayEvent event, Emitter emit) async { + void _decreaseDelay( + DecreaseGarageDoorDelayEvent event, Emitter emit) async { // if (deviceStatus.countdown1 != 0) { try { if (deviceStatus.delay.inMinutes > 10) { - deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay - Duration(minutes: 10)); + deviceStatus = deviceStatus.copyWith( + delay: deviceStatus.delay - Duration(minutes: 10)); } emit(GarageDoorLoadedState(status: deviceStatus)); - add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1')); + add(GarageDoorControlEvent( + deviceId: event.deviceId, + value: deviceStatus.delay.inSeconds, + code: 'countdown_1')); } catch (e) { emit(GarageDoorErrorState(message: e.toString())); } //} } - void _garageDoorControlEvent(GarageDoorControlEvent event, Emitter emit) async { - final oldValue = event.code == 'countdown_1' ? deviceStatus.countdown1 : deviceStatus.switch1; + void _garageDoorControlEvent( + GarageDoorControlEvent event, Emitter emit) async { + final oldValue = event.code == 'countdown_1' + ? deviceStatus.countdown1 + : deviceStatus.switch1; _updateLocalValue(event.code, event.value); emit(GarageDoorLoadedState(status: deviceStatus)); final success = await _runDeBouncer( @@ -258,7 +319,8 @@ class GarageDoorBloc extends Bloc { } } - void _revertValue(String code, dynamic oldValue, Emitter emit) { + void _revertValue( + String code, dynamic oldValue, Emitter emit) { switch (code) { case 'switch_1': if (oldValue is bool) { @@ -267,7 +329,8 @@ class GarageDoorBloc extends Bloc { break; case 'countdown_1': if (oldValue is int) { - deviceStatus = deviceStatus.copyWith(countdown1: oldValue, delay: Duration(seconds: oldValue)); + deviceStatus = deviceStatus.copyWith( + countdown1: oldValue, delay: Duration(seconds: oldValue)); } break; // Add other cases if needed @@ -289,10 +352,20 @@ class GarageDoorBloc extends Bloc { break; case 'countdown_1': if (value is int) { - deviceStatus = deviceStatus.copyWith(countdown1: value, delay: Duration(seconds: value)); + deviceStatus = deviceStatus.copyWith( + countdown1: value, delay: Duration(seconds: value)); + } + break; + case 'countdown_alarm': + if (value is int) { + deviceStatus = deviceStatus.copyWith(countdownAlarm: value); + } + break; + case 'tr_timecon': + if (value is int) { + deviceStatus = deviceStatus.copyWith(trTimeCon: value); } break; - // Add other cases if needed default: break; } diff --git a/lib/pages/device_managment/garage_door/bloc/garage_door_event.dart b/lib/pages/device_managment/garage_door/bloc/garage_door_event.dart index 20758077..515b2a84 100644 --- a/lib/pages/device_managment/garage_door/bloc/garage_door_event.dart +++ b/lib/pages/device_managment/garage_door/bloc/garage_door_event.dart @@ -24,7 +24,8 @@ class GarageDoorControlEvent extends GarageDoorEvent { final dynamic value; final String code; - const GarageDoorControlEvent({required this.deviceId, required this.value, required this.code}); + const GarageDoorControlEvent( + {required this.deviceId, required this.value, required this.code}); @override List get props => [deviceId, value]; @@ -104,7 +105,8 @@ class FetchGarageDoorRecordsEvent extends GarageDoorEvent { final String deviceId; final String code; - const FetchGarageDoorRecordsEvent({required this.deviceId, required this.code}); + const FetchGarageDoorRecordsEvent( + {required this.deviceId, required this.code}); @override List get props => [deviceId, code]; @@ -166,3 +168,15 @@ class InitializeAddScheduleEvent extends GarageDoorEvent { index, ]; } + +class UpdateCountdownAlarmEvent extends GarageDoorEvent { + final int countdownAlarm; + + const UpdateCountdownAlarmEvent(this.countdownAlarm); +} + +class UpdateTrTimeConEvent extends GarageDoorEvent { + final int trTimeCon; + + const UpdateTrTimeConEvent(this.trTimeCon); +} diff --git a/lib/pages/device_managment/garage_door/helper/garage_door_helper.dart b/lib/pages/device_managment/garage_door/helper/garage_door_helper.dart index 55957b53..c30f391d 100644 --- a/lib/pages/device_managment/garage_door/helper/garage_door_helper.dart +++ b/lib/pages/device_managment/garage_door/helper/garage_door_helper.dart @@ -291,6 +291,9 @@ class GarageDoorDialogHelper { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const SizedBox(), + + /// The dialog is closed when the user taps on the close button or when the + /// [GarageDoorBloc] state changes. Text( 'Preferences', style: context.textTheme.titleLarge!.copyWith( @@ -311,13 +314,32 @@ class GarageDoorDialogHelper { child: GestureDetector( onTap: () { context.customAlertDialog( - alertBody: TimeOutAlarmDialogBody(), + alertBody: TimeOutAlarmDialogBody(bloc), title: 'Time Out Alarm', - onConfirm: () {}); + onConfirm: () { + final updatedState = + context.read().state; + if (updatedState + is GarageDoorLoadedState) { + context.read().add( + GarageDoorControlEvent( + deviceId: + updatedState.status.uuid, + code: 'countdown_alarm', + value: updatedState + .status.countdownAlarm, + ), + ); + Navigator.pop(context); + // context.read().add( + // GarageDoorInitialEvent( + // bloc.deviceId)); + } + }); }, child: ToggleWidget( icon: "-1", - value: bloc.deviceStatus.countdownAlarm > 0, + value: state.status.countdownAlarm > 0, code: 'countdown_alarm', deviceId: bloc.deviceId, label: 'Alarm when door is open', @@ -333,12 +355,38 @@ class GarageDoorDialogHelper { child: GestureDetector( onTap: () { context.customAlertDialog( - alertBody: OpeningClosingTimeDialogBody(), + alertBody: OpeningAndClosingTimeDialogBody( + bloc: bloc, + onDurationChanged: (newDuration) { + context.read().add( + UpdateTrTimeConEvent(newDuration), + ); + }, + ), title: 'Opening and Closing Time', - onConfirm: () {}); + onConfirm: () { + final updatedState = + context.read().state; + if (updatedState + is GarageDoorLoadedState) { + context.read().add( + GarageDoorControlEvent( + deviceId: + updatedState.status.uuid, + code: 'tr_timecon', + value: updatedState + .status.trTimeCon, + ), + ); + Navigator.pop(context); + // context.read().add( + // GarageDoorInitialEvent( + // bloc.deviceId)); + } + }); }, child: PresenceDisplayValue( - value: bloc.deviceStatus.trTimeCon.toString(), + value: state.status.trTimeCon.toString(), postfix: 'sec', description: 'Opening & Closing Time', ), diff --git a/lib/pages/device_managment/garage_door/widgets/opening_clsoing_time_dialog_body.dart b/lib/pages/device_managment/garage_door/widgets/opening_clsoing_time_dialog_body.dart index ea76d901..843bac9b 100644 --- a/lib/pages/device_managment/garage_door/widgets/opening_clsoing_time_dialog_body.dart +++ b/lib/pages/device_managment/garage_door/widgets/opening_clsoing_time_dialog_body.dart @@ -1,13 +1,53 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_state.dart'; +import 'package:syncrow_web/pages/device_managment/garage_door/widgets/seconds_picker.dart'; -class OpeningClosingTimeDialogBody extends StatelessWidget { - const OpeningClosingTimeDialogBody({super.key}); +class OpeningAndClosingTimeDialogBody extends StatefulWidget { + final ValueChanged onDurationChanged; + final GarageDoorBloc bloc; + + OpeningAndClosingTimeDialogBody({ + required this.onDurationChanged, + required this.bloc, + }); + + @override + _OpeningAndClosingTimeDialogBodyState createState() => + _OpeningAndClosingTimeDialogBodyState(); +} + +class _OpeningAndClosingTimeDialogBodyState + extends State { + late int durationInSeconds; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + final currentState = widget.bloc.state; + if (currentState is GarageDoorLoadedState) { + setState(() { + durationInSeconds = currentState.status.trTimeCon; + }); + } + } @override Widget build(BuildContext context) { return Container( - width: 350, - child: Text('asdasd'), + height: 120, + color: Colors.white, + child: SecondsPicker( + initialSeconds: durationInSeconds, + onSecondsChanged: (newSeconds) { + setState(() { + durationInSeconds = newSeconds; + }); + widget.onDurationChanged(newSeconds); + }, + ), ); } } diff --git a/lib/pages/device_managment/garage_door/widgets/seconds_picker.dart b/lib/pages/device_managment/garage_door/widgets/seconds_picker.dart new file mode 100644 index 00000000..491be37b --- /dev/null +++ b/lib/pages/device_managment/garage_door/widgets/seconds_picker.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +class SecondsPicker extends StatefulWidget { + final int initialSeconds; + final ValueChanged onSecondsChanged; + + SecondsPicker({ + required this.initialSeconds, + required this.onSecondsChanged, + }); + + @override + _SecondsPickerState createState() => _SecondsPickerState(); +} + +class _SecondsPickerState extends State { + late FixedExtentScrollController _scrollController; + + @override + void initState() { + super.initState(); + _scrollController = FixedExtentScrollController( + initialItem: widget.initialSeconds, + ); + } + + @override + Widget build(BuildContext context) { + return Container( + height: 120, + color: Colors.white, + child: ListWheelScrollView.useDelegate( + controller: _scrollController, + itemExtent: 48, + onSelectedItemChanged: (index) { + widget.onSecondsChanged(index); + }, + physics: const FixedExtentScrollPhysics(), + childDelegate: ListWheelChildBuilderDelegate( + builder: (context, index) { + return Center( + child: Text( + '$index sec', + style: const TextStyle(fontSize: 24), + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/device_managment/garage_door/widgets/time_out_alarm_dialog_body.dart b/lib/pages/device_managment/garage_door/widgets/time_out_alarm_dialog_body.dart index 948f8190..541ab9e4 100644 --- a/lib/pages/device_managment/garage_door/widgets/time_out_alarm_dialog_body.dart +++ b/lib/pages/device_managment/garage_door/widgets/time_out_alarm_dialog_body.dart @@ -1,13 +1,49 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_event.dart'; +import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_state.dart'; -class TimeOutAlarmDialogBody extends StatelessWidget { - const TimeOutAlarmDialogBody({super.key}); +class TimeOutAlarmDialogBody extends StatefulWidget { + TimeOutAlarmDialogBody(this.bloc); + final GarageDoorBloc bloc; + + @override + _TimeOutAlarmDialogBodyState createState() => _TimeOutAlarmDialogBodyState(); +} + +class _TimeOutAlarmDialogBodyState extends State { + int durationInSeconds = 0; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + final currentState = widget.bloc.state; + if (currentState is GarageDoorLoadedState) { + if (currentState.status.countdownAlarm != 0) { + setState(() { + durationInSeconds = currentState.status.countdownAlarm; + }); + } + } + } @override Widget build(BuildContext context) { return Container( - width: 350, - child: Text('asdasd'), + height: 120, + color: Colors.white, + child: CupertinoTimerPicker( + itemExtent: 120, + mode: CupertinoTimerPickerMode.hm, + initialTimerDuration: Duration(seconds: durationInSeconds), + onTimerDurationChanged: (newDuration) { + widget.bloc.add( + UpdateCountdownAlarmEvent(newDuration.inSeconds), + ); + }, + ), ); } }