From 5aec3d37fb1d2f50644cd5c4fb4dc4c24d337f55 Mon Sep 17 00:00:00 2001 From: mohammad Date: Wed, 7 Aug 2024 17:20:19 +0300 Subject: [PATCH] fix password --- .../bloc/smart_door_bloc/smart_door_bloc.dart | 84 +++++++++++++++-- .../smart_door_bloc/smart_door_event.dart | 8 ++ .../view/widgets/hour_picker_dialog.dart | 92 +++++++++++++++++++ .../view/widgets/name_time_widget.dart | 4 +- .../offline_one_time_password_page.dart | 16 ++-- .../offline_timeLimit_password_page.dart | 19 ++-- .../smart_door/timelimited_password_page.dart | 14 +-- lib/services/api/devices_api.dart | 4 +- 8 files changed, 199 insertions(+), 42 deletions(-) create mode 100644 lib/features/devices/view/widgets/hour_picker_dialog.dart diff --git a/lib/features/devices/bloc/smart_door_bloc/smart_door_bloc.dart b/lib/features/devices/bloc/smart_door_bloc/smart_door_bloc.dart index cdaab9d..9ba8053 100644 --- a/lib/features/devices/bloc/smart_door_bloc/smart_door_bloc.dart +++ b/lib/features/devices/bloc/smart_door_bloc/smart_door_bloc.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart'; @@ -12,6 +13,7 @@ import 'package:syncrow_app/features/devices/model/smart_door_model.dart'; import 'package:syncrow_app/features/devices/model/status_model.dart'; import 'package:syncrow_app/features/devices/model/create_temporary_password_model.dart'; import 'package:syncrow_app/features/devices/model/temporary_password_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/hour_picker_dialog.dart'; import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; @@ -32,7 +34,8 @@ class SmartDoorBloc extends Bloc { on(setStartEndTime); on(changeTime); on(generate7DigitNumber); - on(selectTime); + on(selectTimeOfLinePassword); + on(selectTimeOnlinePassword); on(deletePassword); on(generateAndSavePasswordTimeLimited); on(generateAndSavePasswordOneTime); @@ -66,7 +69,6 @@ class SmartDoorBloc extends Bloc { return passwordController.text; } - Future generateAndSavePasswordOneTime (GenerateAndSavePasswordOneTimeEvent event, Emitter emit) async { try { if (isSavingPassword) return; @@ -76,6 +78,10 @@ class SmartDoorBloc extends Bloc { ApiResponse pass= ApiResponse.fromJson(res); passwordController.text =pass.data.offlineTempPassword; passwordId=pass.data.offlineTempPasswordId; + + Future.delayed(const Duration(seconds: 1), () { + Clipboard.setData(ClipboardData(text: passwordController.text)); + }); emit(const GeneratePasswordOneTimestate(generated: true)); } catch (_) { emit(FailedState(errorMessage: _.toString())); @@ -108,6 +114,8 @@ class SmartDoorBloc extends Bloc { doorLockUuid:deviceId , passwordId:passwordId ); + add(InitialOneTimePassword()); + add(InitialTimeLimitPassword()); emit(UpdateState(smartDoorModel: deviceStatus)); } catch (e) { emit(FailedState(errorMessage: e.toString())); @@ -150,6 +158,7 @@ class SmartDoorBloc extends Bloc { if (response is List) { timeLimitPasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList(); } + emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!)); } catch (e) { emit(FailedState(errorMessage: e.toString())); @@ -192,7 +201,56 @@ class SmartDoorBloc extends Bloc { emit(UpdateState(smartDoorModel: deviceStatus)); } - Future selectTime(SelectTimeEvent event, Emitter emit) async { + + Future selectTimeOfLinePassword(SelectTimeEvent event, Emitter emit) async { + emit(ChangeTimeState()); + final DateTime? picked = await showDatePicker( + context: event.context, + initialDate: DateTime.now(), + firstDate: DateTime.now(), + lastDate: DateTime(2101), + ); + if (picked != null) { + final TimeOfDay? timePicked = await showHourPicker( + context: event.context, + initialTime: TimeOfDay.now(), + ); + if (timePicked != null) { + final selectedDateTime = DateTime( + picked.year, + picked.month, + picked.day, + timePicked.hour, + 0, + ); + final selectedTimestamp = DateTime( + selectedDateTime.year, + selectedDateTime.month, + selectedDateTime.day, + selectedDateTime.hour, + selectedDateTime.minute, + ).millisecondsSinceEpoch ~/ 1000; // Divide by 1000 to remove milliseconds + if (event.isEffective) { + if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) { + CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.'); + } else { + effectiveTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds + effectiveTimeTimeStamp = selectedTimestamp; + } + } else { + if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { + CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.'); + } else { + expirationTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds + expirationTimeTimeStamp = selectedTimestamp; + } + } + emit(TimeSelectedState()); + } + } + } + + Future selectTimeOnlinePassword(SelectTimeOnlinePasswordEvent event, Emitter emit) async { emit(ChangeTimeState()); final DateTime? picked = await showDatePicker( context: event.context, @@ -294,16 +352,22 @@ class SmartDoorBloc extends Bloc { try { isSavingPassword = true; emit(LoadingInitialState()); - var res = await DevicesAPI.generateMultiTimePassword(deviceId: deviceId, + var res = await DevicesAPI.generateMultiTimePassword( + deviceId: deviceId, effectiveTime: effectiveTimeTimeStamp.toString(), - invalidTime: expirationTimeTimeStamp.toString(), ); + invalidTime: expirationTimeTimeStamp.toString(), + ); ApiResponse pass= ApiResponse.fromJson(res); passwordController.text =pass.data.offlineTempPassword; passwordId=pass.data.offlineTempPasswordId; CustomSnackBar.displaySnackBar('Save Successfully'); + add(InitialTimeLimitPassword()); + Future.delayed(const Duration(seconds: 1), () { + Clipboard.setData(ClipboardData(text: passwordController.text)); + }); emit(const GeneratePasswordOneTimestate(generated: true)); } catch (_) { - emit(FailedState(errorMessage: e.toString())); + add(InitialPasswordsPage()); } finally { isSavingPassword = false; @@ -328,6 +392,7 @@ class SmartDoorBloc extends Bloc { CustomSnackBar.displaySnackBar('Password less than 7'); return true; } + if (passwordController.text.isEmpty) { CustomSnackBar.displaySnackBar('Password required'); return true; @@ -336,20 +401,24 @@ class SmartDoorBloc extends Bloc { CustomSnackBar.displaySnackBar('Password name required'); return true; } + if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) { CustomSnackBar.displaySnackBar('Select effective time'); return true; } + if (expirationTime == 'Select Time' || expirationTimeTimeStamp == null) { CustomSnackBar.displaySnackBar('Select expiration time'); return true; } + if (repeat == true && (endTime == null || startTime == null || selectedDays == null)) { CustomSnackBar.displaySnackBar('Start Time and End time and the days required '); return true; } return false; } + bool timeLimitValidate() { if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) { @@ -392,3 +461,6 @@ class SmartDoorBloc extends Bloc { } + + + diff --git a/lib/features/devices/bloc/smart_door_bloc/smart_door_event.dart b/lib/features/devices/bloc/smart_door_bloc/smart_door_event.dart index b73a381..5693169 100644 --- a/lib/features/devices/bloc/smart_door_bloc/smart_door_event.dart +++ b/lib/features/devices/bloc/smart_door_bloc/smart_door_event.dart @@ -53,6 +53,14 @@ class SelectTimeEvent extends SmartDoorEvent { List get props => [context,isEffective]; } +class SelectTimeOnlinePasswordEvent extends SmartDoorEvent { + final BuildContext context; + final bool isEffective; + const SelectTimeOnlinePasswordEvent({required this.context,required this.isEffective}); + @override + List get props => [context,isEffective]; +} + class ToggleRepeatEvent extends SmartDoorEvent {} class SetStartEndTimeEvent extends SmartDoorEvent { final bool val; diff --git a/lib/features/devices/view/widgets/hour_picker_dialog.dart b/lib/features/devices/view/widgets/hour_picker_dialog.dart new file mode 100644 index 0000000..63e95e2 --- /dev/null +++ b/lib/features/devices/view/widgets/hour_picker_dialog.dart @@ -0,0 +1,92 @@ + + +import 'package:flutter/material.dart'; + +class HourPickerDialog extends StatefulWidget { + final TimeOfDay initialTime; + HourPickerDialog({required this.initialTime}); + + @override + _HourPickerDialogState createState() => _HourPickerDialogState(); +} + +class _HourPickerDialogState extends State { + late int _selectedHour; + bool _isPm = false; + + @override + void initState() { + super.initState(); + _selectedHour = widget.initialTime.hour > 12 ? widget.initialTime.hour - 12 : widget.initialTime.hour; + _isPm = widget.initialTime.period == DayPeriod.pm; + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text('Select Hour'), + content: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + DropdownButton( + value: _selectedHour, + items: List.generate(12, (index) { + int displayHour = index + 1; + return DropdownMenuItem( + value: displayHour, + child: Text(displayHour.toString()), + ); + }), + onChanged: (value) { + setState(() { + _selectedHour = value!; + }); + }, + ), + SizedBox(width: 16.0), + DropdownButton( + value: _isPm, + items: [ + DropdownMenuItem( + value: false, + child: Text('AM'), + ), + DropdownMenuItem( + value: true, + child: Text('PM'), + ), + ], + onChanged: (value) { + setState(() { + _isPm = value!; + }); + }, + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(null), + child: Text('Cancel'), + ), + TextButton( + onPressed: () { + int hour = _isPm ? _selectedHour + 12 : _selectedHour; + Navigator.of(context).pop(TimeOfDay(hour: hour, minute: 0)); + }, + child: Text('OK'), + ), + ], + ); + } +} + +Future showHourPicker({ + required BuildContext context, + required TimeOfDay initialTime, +}) { + return showDialog( + context: context, + builder: (context) => HourPickerDialog(initialTime: initialTime), + ); +} diff --git a/lib/features/devices/view/widgets/name_time_widget.dart b/lib/features/devices/view/widgets/name_time_widget.dart index d54ecf4..5adbe2e 100644 --- a/lib/features/devices/view/widgets/name_time_widget.dart +++ b/lib/features/devices/view/widgets/name_time_widget.dart @@ -60,7 +60,7 @@ class NameTimeWidget extends StatelessWidget { child: InkWell( onTap: () { - BlocProvider.of(context).add(SelectTimeEvent(context: context, isEffective: true)); + BlocProvider.of(context).add(SelectTimeOnlinePasswordEvent(context: context, isEffective: true)); }, child: Text( BlocProvider.of(context).effectiveTime, @@ -92,7 +92,7 @@ class NameTimeWidget extends StatelessWidget { child: InkWell( onTap: () { BlocProvider.of(context).add( - SelectTimeEvent( + SelectTimeOnlinePasswordEvent( context: context, isEffective: false)); }, child: Text( diff --git a/lib/features/devices/view/widgets/offline_one_time_password_page.dart b/lib/features/devices/view/widgets/offline_one_time_password_page.dart index 8f8ddec..6c560cd 100644 --- a/lib/features/devices/view/widgets/offline_one_time_password_page.dart +++ b/lib/features/devices/view/widgets/offline_one_time_password_page.dart @@ -13,6 +13,7 @@ import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/door_lock_button.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; +import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; @@ -28,11 +29,8 @@ class OfflineOneTimePasswordPage extends StatelessWidget { create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!), child: BlocConsumer(listener: (context, state) { if (state is FailedState) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(state.errorMessage), - backgroundColor: Colors.red, - ), + CustomSnackBar.displaySnackBar( + state.errorMessage ); } if (state is IsRepeatState){ @@ -104,6 +102,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget { Expanded( child: Row( children: [ + Expanded( child: BodyLarge( style: const TextStyle( @@ -114,8 +113,9 @@ class OfflineOneTimePasswordPage extends StatelessWidget { wordSpacing: 2), textAlign: TextAlign.center, text: smartDoorBloc.passwordController.text, - fontSize: 25, + fontSize: 23, ),), + IconButton( onPressed: () async { await Clipboard.setData(ClipboardData( @@ -166,7 +166,6 @@ class OfflineOneTimePasswordPage extends StatelessWidget { ], ), - ], ), ), @@ -195,9 +194,6 @@ class OfflineOneTimePasswordPage extends StatelessWidget { onPressed: () async { if(generated==false){ smartDoorBloc.add(GenerateAndSavePasswordOneTimeEvent(context: context)); - await Clipboard.setData( - ClipboardData(text: smartDoorBloc.passwordController.text) - ); }else{ if(smartDoorBloc.passwordNameController.text.isNotEmpty){ smartDoorBloc.add(RenamePasswordEvent()); diff --git a/lib/features/devices/view/widgets/smart_door/offline_timeLimit_password_page.dart b/lib/features/devices/view/widgets/smart_door/offline_timeLimit_password_page.dart index 9cb26da..9a55e82 100644 --- a/lib/features/devices/view/widgets/smart_door/offline_timeLimit_password_page.dart +++ b/lib/features/devices/view/widgets/smart_door/offline_timeLimit_password_page.dart @@ -11,6 +11,7 @@ import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/door_lock_button.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; +import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; @@ -27,11 +28,8 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget { child: BlocConsumer( listener: (context, state) { if (state is FailedState) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(state.errorMessage), - backgroundColor: Colors.red, - ), + CustomSnackBar.displaySnackBar( + state.errorMessage ); } if (state is IsRepeatState) { @@ -240,8 +238,7 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget { ), const BodyMedium( textAlign: TextAlign.center, - text: - 'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.', + text: 'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.', fontWeight: FontWeight.normal, fontColor: ColorsManager.grayColor, ), @@ -259,14 +256,10 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget { backgroundColor: ColorsManager.primaryColor, onPressed: () async { if (generated == false) { - smartDoorBloc.add( - GenerateAndSavePasswordTimeLimitEvent(context: context)); - await Clipboard.setData( - ClipboardData(text: smartDoorBloc.passwordController.text) - ); + smartDoorBloc.add(GenerateAndSavePasswordTimeLimitEvent(context: context)); } else { if(smartDoorBloc.passwordNameController.text.isNotEmpty){ - smartDoorBloc.add(RenamePasswordEvent()); + smartDoorBloc.add(RenamePasswordEvent()); } Navigator.of(context).pop(true); } diff --git a/lib/features/devices/view/widgets/smart_door/timelimited_password_page.dart b/lib/features/devices/view/widgets/smart_door/timelimited_password_page.dart index 644c075..fce92b9 100644 --- a/lib/features/devices/view/widgets/smart_door/timelimited_password_page.dart +++ b/lib/features/devices/view/widgets/smart_door/timelimited_password_page.dart @@ -9,6 +9,7 @@ import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/generated/assets.dart'; +import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'door_dialog.dart'; @@ -22,11 +23,8 @@ class TimeLimitedPasswordPage extends StatelessWidget { child: BlocConsumer( listener: (context, state) { if (state is FailedState) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(state.errorMessage), - backgroundColor: Colors.red, - ), + CustomSnackBar.displaySnackBar( + state.errorMessage ); } }, @@ -40,10 +38,8 @@ class TimeLimitedPasswordPage extends StatelessWidget { Navigator.of(context).push( MaterialPageRoute(builder: (context) => CreateOfflineTimeLimitPasswordPage(deviceId: deviceId,) )).then((result) { - if (result != null) { - smartDoorBloc.add(InitialTimeLimitPassword()); - smartDoorBloc.add(InitialTimeLimitPassword()); - } + smartDoorBloc.add(InitialTimeLimitPassword()); + smartDoorBloc.add(InitialTimeLimitPassword()); }); }, icon: const Icon(Icons.add) diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index e379ba7..2863668 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -197,13 +197,13 @@ class DevicesAPI { required String invalidTime, required String deviceId, List? scheduleList,}) async { - Map body = { "name": name, "password": password, "effectiveTime": effectiveTime, "invalidTime": invalidTime, }; + print('createPassword =$body'); if (scheduleList != null) { body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); } @@ -235,7 +235,7 @@ class DevicesAPI { try { final response = await _httpService.post( path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), - showServerMessage: false, + showServerMessage: true, body: { "effectiveTime": effectiveTime, "invalidTime": invalidTime