diff --git a/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart b/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart index ee47e94..d4aa759 100644 --- a/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart +++ b/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart @@ -34,11 +34,14 @@ class GarageDoorBloc extends Bloc { on(openCloseGarageDoor); on(_getCounterValue); on(_setCounterValue); + on(_setTimeOutAlarm); on(_onTickTimer); on(_fetchWizardStatus); on(_groupAllOn); on(_groupAllOff); on(_changeFirstWizardSwitch); + on(_toggleAlarmEvent); + //_toggleAlarmEvent } void _onClose(OnClose event, Emitter emit) { _timer?.cancel(); @@ -84,6 +87,32 @@ class GarageDoorBloc extends Bloc { } } + void _toggleAlarmEvent( + ToggleAlarmEvent event, + Emitter emit, + ) async { + emit(LoadingNewSate(doorSensor: deviceStatus)); + + try { + deviceStatus.doorState1 = event.isEnabled; + + emit(UpdateState(garageSensor: deviceStatus)); + + await DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: GDId, + code: 'door_state_1', + value: event.isEnabled, + ), + GDId, + ); + + emit(UpdateState(garageSensor: deviceStatus)); + } catch (e) { + emit(GarageDoorFailedState(errorMessage: e.toString())); + } + } + void _toggleClosingReminder(ToggleClosingReminderEvent event, Emitter emit) async { emit(LoadingNewSate(doorSensor: deviceStatus)); @@ -563,4 +592,29 @@ class GarageDoorBloc extends Bloc { add(InitialEvent(groupScreen: oneGangGroup)); } } + + void _setTimeOutAlarm( + SetTimeOutValue event, Emitter emit) async { + emit(LoadingNewSate(doorSensor: deviceStatus)); + int seconds = 0; + try { + seconds = event.duration.inSeconds; + final response = await DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: GDId, code: 'countdown_alarm', value: seconds), + GDId); + + if (response['success'] ?? false) { + deviceStatus.countdownAlarm = seconds; + CustomSnackBar.displaySnackBar('Save Successfully'); + add(GetScheduleEvent()); + } else { + emit(const GarageDoorFailedState(errorMessage: 'Something went wrong')); + return; + } + } catch (e) { + emit(GarageDoorFailedState(errorMessage: e.toString())); + return; + } + } } diff --git a/lib/features/devices/bloc/garage_door_bloc/garage_door_event.dart b/lib/features/devices/bloc/garage_door_bloc/garage_door_event.dart index 7114ce3..83e7b07 100644 --- a/lib/features/devices/bloc/garage_door_bloc/garage_door_event.dart +++ b/lib/features/devices/bloc/garage_door_bloc/garage_door_event.dart @@ -39,13 +39,13 @@ class GetCounterEvent extends GarageDoorEvent { List get props => [deviceCode]; } -class ToggleLowBatteryEvent extends GarageDoorEvent { - final bool isLowBatteryEnabled; +class ToggleAlarmEvent extends GarageDoorEvent { + final String isEnabled; - const ToggleLowBatteryEvent(this.isLowBatteryEnabled); + const ToggleAlarmEvent(this.isEnabled); @override - List get props => [isLowBatteryEnabled]; + List get props => [isEnabled]; } class ToggleClosingReminderEvent extends GarageDoorEvent { @@ -74,6 +74,14 @@ class SetCounterValue extends GarageDoorEvent { List get props => [duration, deviceCode]; } +class SetTimeOutValue extends GarageDoorEvent { + final Duration duration; + final String deviceCode; + const SetTimeOutValue({required this.duration, required this.deviceCode}); + @override + List get props => [duration, deviceCode]; +} + class StartTimer extends GarageDoorEvent { final int duration; diff --git a/lib/features/devices/bloc/wall_sensor_bloc/wall_sensor_bloc.dart b/lib/features/devices/bloc/wall_sensor_bloc/wall_sensor_bloc.dart index df3bdd2..36212c5 100644 --- a/lib/features/devices/bloc/wall_sensor_bloc/wall_sensor_bloc.dart +++ b/lib/features/devices/bloc/wall_sensor_bloc/wall_sensor_bloc.dart @@ -21,7 +21,8 @@ class WallSensorBloc extends Bloc { } void _fetchCeilingSensorStatus( - InitialEvent event, Emitter emit) async { + InitialEvent event, + Emitter emit) async { emit(LoadingInitialState()); try { var response = await DevicesAPI.getDeviceStatus(deviceId); diff --git a/lib/features/devices/view/widgets/garage_door/garage_preferences_settings.dart b/lib/features/devices/view/widgets/garage_door/garage_preferences_settings.dart index 72ea127..8aa81a9 100644 --- a/lib/features/devices/view/widgets/garage_door/garage_preferences_settings.dart +++ b/lib/features/devices/view/widgets/garage_door/garage_preferences_settings.dart @@ -18,7 +18,8 @@ class PreferencesPage extends StatelessWidget { return DefaultScaffold( title: 'Preferences', child: BlocProvider( - create: (context) => GarageDoorBloc(GDId: GDId)..add(const GarageDoorInitial()), + create: (context) => + GarageDoorBloc(GDId: GDId)..add(const GarageDoorInitial()), child: BlocBuilder( builder: (context, state) { final garageDoorBloc = BlocProvider.of(context); @@ -26,7 +27,9 @@ class PreferencesPage extends StatelessWidget { return state is GarageDoorLoadingState ? const Center( child: DefaultContainer( - width: 50, height: 50, child: CircularProgressIndicator()), + width: 50, + height: 50, + child: CircularProgressIndicator()), ) : Column( children: [ @@ -49,14 +52,42 @@ class PreferencesPage extends StatelessWidget { height: 50, child: ListTile( contentPadding: EdgeInsets.zero, - leading: const BodyMedium( - text: 'Alarm when door is open', - fontWeight: FontWeight.normal, + leading: InkWell( + onTap: () { + showDialog( + context: context, + builder: (context) { + return TimeoutDialog( + duration: Duration( + seconds: garageDoorBloc + .deviceStatus + .countdownAlarm), + title: 'Timeout Alarm', + cancelTab: () { + Navigator.of(context).pop(); + }, + confirmTab: (selectedSecond) { + garageDoorBloc.add( + SetTimeOutValue( + deviceCode: + 'countdown_alarm', + duration: + selectedSecond)); + Navigator.of(context).pop(); + }, + ); + }); + }, + child: const BodyMedium( + text: 'Alarm when door is open', + fontWeight: FontWeight.normal, + ), ), trailing: Container( width: 100, child: Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.end, children: [ Container( height: 30, @@ -64,18 +95,25 @@ class PreferencesPage extends StatelessWidget { color: ColorsManager.graysColor, ), Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: garageDoorBloc.lowBattery, - onChanged: (value) { - // context - // .read() - // .add( - // ToggleLowBatteryEvent( - // value)); - }, - applyTheme: true, - )), + scale: .8, + child: CupertinoSwitch( + value: garageDoorBloc.deviceStatus + .doorState1 == + 'unclosed_time', + onChanged: (value) { + context + .read() + .add( + ToggleAlarmEvent( + value + ? 'unclosed_time' + : 'close_time_alarm', + ), + ); + }, + applyTheme: true, + ), + ), ], ), )), @@ -103,12 +141,15 @@ class PreferencesPage extends StatelessWidget { builder: (context) { return SecondDialog( label2: 'Close', - initialSelectedLabel: garageDoorBloc.secondSelected.toString(), + initialSelectedLabel: garageDoorBloc + .secondSelected + .toString(), cancelTab: () { Navigator.of(context).pop(); }, confirmTab: (v) { - garageDoorBloc.add(SelectSecondsEvent(seconds: v)); + garageDoorBloc + .add(SelectSecondsEvent(seconds: v)); Navigator.of(context).pop(); }, title: 'Control', @@ -129,8 +170,10 @@ class PreferencesPage extends StatelessWidget { height: 90, width: 120, child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ BodyMedium( fontColor: ColorsManager.textGray, @@ -156,6 +199,7 @@ class PreferencesPage extends StatelessWidget { )); } } +//Timeout class SecondDialog extends StatefulWidget { final String label1; @@ -183,15 +227,12 @@ class SecondDialog extends StatefulWidget { } class _SecondDialogState extends State { - // late String _selectedOption; late int selectedSecond; @override void initState() { super.initState(); - // Parse the initialSelectedLabel as an integer. Default to 10 if invalid or not provided. selectedSecond = int.tryParse(widget.initialSelectedLabel ?? '10') ?? 10; - // _selectedOption = widget.initialSelectedLabel ?? ''; } @override @@ -229,7 +270,6 @@ class _SecondDialogState extends State { child: CupertinoPicker( itemExtent: 40.0, scrollController: FixedExtentScrollController( - // Set the initial position based on selectedSecond initialItem: selectedSecond - 10, ), onSelectedItemChanged: (int index) { @@ -242,7 +282,9 @@ class _SecondDialogState extends State { child: BodyLarge( text: (index + 10).toString().padLeft(2, '0'), style: const TextStyle( - fontWeight: FontWeight.w400, fontSize: 30, color: Colors.blue), + fontWeight: FontWeight.w400, + fontSize: 30, + color: Colors.blue), ), ); }), @@ -326,3 +368,153 @@ class _SecondDialogState extends State { ); } } + +class TimeoutDialog extends StatefulWidget { + final String title; + final Function(String)? onTapLabel1; + final Function()? cancelTab; + final Function(Duration timeSelected)? confirmTab; + final Duration? duration; + + TimeoutDialog({ + required this.title, + this.onTapLabel1, + required this.cancelTab, + required this.confirmTab, + this.duration, + }); + + @override + _TimeoutDialogState createState() => _TimeoutDialogState(); +} + +class _TimeoutDialogState extends State { + late int selectedSecond; + Duration duration = Duration.zero; + int countNum = 0; + @override + void initState() { + super.initState(); + duration = widget.duration!; + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + contentPadding: EdgeInsets.zero, + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox( + height: 10, + ), + BodyLarge( + text: widget.title, + fontWeight: FontWeight.w700, + fontColor: ColorsManager.primaryColor, + fontSize: 16, + ), + const Padding( + padding: EdgeInsets.only(left: 15, right: 15), + child: Divider( + color: ColorsManager.textGray, + ), + ), + Padding( + padding: const EdgeInsets.only(left: 15, right: 15, bottom: 10), + child: Column( + children: [ + Center( + child: Container( + height: 150, + width: MediaQuery.of(context).size.width * 1, + child: CupertinoTimerPicker( + initialTimerDuration: duration, + mode: CupertinoTimerPickerMode.hm, + onTimerDurationChanged: (Duration newDuration) { + duration = newDuration; + }, + ), + ), + ), + ], + ), + ), + Row( + children: [ + Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border( + right: BorderSide( + color: ColorsManager.textGray, + width: 0.5, + ), + top: BorderSide( + color: ColorsManager.textGray, + width: 1.0, + ), + )), + child: SizedBox( + child: InkWell( + onTap: widget.cancelTab, + child: const Padding( + padding: EdgeInsets.all(15), + child: Center( + child: Text( + 'Cancel', + style: TextStyle( + color: ColorsManager.textGray, + fontSize: 14, + fontWeight: FontWeight.w400), + ), + ), + ), + ), + ), + ), + ), + Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border( + left: BorderSide( + color: ColorsManager.textGray, + width: 0.5, + ), + top: BorderSide( + color: ColorsManager.textGray, + width: 1.0, + ), + )), + child: InkWell( + onTap: () { + widget.confirmTab?.call(duration); + }, + child: const Padding( + padding: EdgeInsets.all(15), + child: Center( + child: Text( + 'Confirm', + style: TextStyle( + color: ColorsManager.primaryColor, + fontSize: 14, + fontWeight: FontWeight.w400), + ), + ), + )), + )) + ], + ) + ], + ), + ); + } + + String _formatDuration(int seconds) { + final hours = (seconds ~/ 3600).toString().padLeft(2, '0'); + final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0'); + final secs = (seconds % 60).toString().padLeft(2, '0'); + return '$hours:$minutes:$secs'; + } +} diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index e4a6188..bebdad2 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -38,6 +38,7 @@ class DevicesAPI { body: controlModel.toJson(), showServerMessage: true, expectedResponseModel: (json) { + print(json); return json; }, ); diff --git a/pubspec.yaml b/pubspec.yaml index 8d4d265..2eadacd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ description: This is the mobile application project, developed with Flutter for # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: "none" # Remove this line if you wish to publish to pub.dev -version: 1.0.3+26 +version: 1.0.4+26 environment: sdk: ">=3.0.6 <4.0.0"