Merge pull request #45 from SyncrowIOT/fix_bugs_doorlock_qa

fix password
This commit is contained in:
Abdullah
2024-08-07 17:25:48 +03:00
committed by GitHub
8 changed files with 199 additions and 42 deletions

View File

@ -1,6 +1,7 @@
import 'dart:math'; import 'dart:math';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.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/status_model.dart';
import 'package:syncrow_app/features/devices/model/create_temporary_password_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/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/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.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/color_manager.dart';
@ -32,7 +34,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
on<SetStartEndTimeEvent>(setStartEndTime); on<SetStartEndTimeEvent>(setStartEndTime);
on<ChangeTimeEvent>(changeTime); on<ChangeTimeEvent>(changeTime);
on<GeneratePasswordEvent>(generate7DigitNumber); on<GeneratePasswordEvent>(generate7DigitNumber);
on<SelectTimeEvent>(selectTime); on<SelectTimeEvent>(selectTimeOfLinePassword);
on<SelectTimeOnlinePasswordEvent>(selectTimeOnlinePassword);
on<DeletePasswordEvent>(deletePassword); on<DeletePasswordEvent>(deletePassword);
on<GenerateAndSavePasswordTimeLimitEvent>(generateAndSavePasswordTimeLimited); on<GenerateAndSavePasswordTimeLimitEvent>(generateAndSavePasswordTimeLimited);
on<GenerateAndSavePasswordOneTimeEvent>(generateAndSavePasswordOneTime); on<GenerateAndSavePasswordOneTimeEvent>(generateAndSavePasswordOneTime);
@ -66,7 +69,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
return passwordController.text; return passwordController.text;
} }
Future generateAndSavePasswordOneTime (GenerateAndSavePasswordOneTimeEvent event, Emitter<SmartDoorState> emit) async { Future generateAndSavePasswordOneTime (GenerateAndSavePasswordOneTimeEvent event, Emitter<SmartDoorState> emit) async {
try { try {
if (isSavingPassword) return; if (isSavingPassword) return;
@ -76,6 +78,10 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
ApiResponse pass= ApiResponse.fromJson(res); ApiResponse pass= ApiResponse.fromJson(res);
passwordController.text =pass.data.offlineTempPassword; passwordController.text =pass.data.offlineTempPassword;
passwordId=pass.data.offlineTempPasswordId; passwordId=pass.data.offlineTempPasswordId;
Future.delayed(const Duration(seconds: 1), () {
Clipboard.setData(ClipboardData(text: passwordController.text));
});
emit(const GeneratePasswordOneTimestate(generated: true)); emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) { } catch (_) {
emit(FailedState(errorMessage: _.toString())); emit(FailedState(errorMessage: _.toString()));
@ -108,6 +114,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
doorLockUuid:deviceId , doorLockUuid:deviceId ,
passwordId:passwordId passwordId:passwordId
); );
add(InitialOneTimePassword());
add(InitialTimeLimitPassword());
emit(UpdateState(smartDoorModel: deviceStatus)); emit(UpdateState(smartDoorModel: deviceStatus));
} catch (e) { } catch (e) {
emit(FailedState(errorMessage: e.toString())); emit(FailedState(errorMessage: e.toString()));
@ -150,6 +158,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
if (response is List) { if (response is List) {
timeLimitPasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList(); timeLimitPasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList();
} }
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!)); emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) { } catch (e) {
emit(FailedState(errorMessage: e.toString())); emit(FailedState(errorMessage: e.toString()));
@ -192,7 +201,56 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
emit(UpdateState(smartDoorModel: deviceStatus)); emit(UpdateState(smartDoorModel: deviceStatus));
} }
Future<void> selectTime(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
Future<void> selectTimeOfLinePassword(SelectTimeEvent event, Emitter<SmartDoorState> 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<void> selectTimeOnlinePassword(SelectTimeOnlinePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState()); emit(ChangeTimeState());
final DateTime? picked = await showDatePicker( final DateTime? picked = await showDatePicker(
context: event.context, context: event.context,
@ -294,16 +352,22 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
try { try {
isSavingPassword = true; isSavingPassword = true;
emit(LoadingInitialState()); emit(LoadingInitialState());
var res = await DevicesAPI.generateMultiTimePassword(deviceId: deviceId, var res = await DevicesAPI.generateMultiTimePassword(
deviceId: deviceId,
effectiveTime: effectiveTimeTimeStamp.toString(), effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString(), ); invalidTime: expirationTimeTimeStamp.toString(),
);
ApiResponse pass= ApiResponse.fromJson(res); ApiResponse pass= ApiResponse.fromJson(res);
passwordController.text =pass.data.offlineTempPassword; passwordController.text =pass.data.offlineTempPassword;
passwordId=pass.data.offlineTempPasswordId; passwordId=pass.data.offlineTempPasswordId;
CustomSnackBar.displaySnackBar('Save Successfully'); CustomSnackBar.displaySnackBar('Save Successfully');
add(InitialTimeLimitPassword());
Future.delayed(const Duration(seconds: 1), () {
Clipboard.setData(ClipboardData(text: passwordController.text));
});
emit(const GeneratePasswordOneTimestate(generated: true)); emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) { } catch (_) {
emit(FailedState(errorMessage: e.toString())); add(InitialPasswordsPage());
} }
finally { finally {
isSavingPassword = false; isSavingPassword = false;
@ -328,6 +392,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Password less than 7'); CustomSnackBar.displaySnackBar('Password less than 7');
return true; return true;
} }
if (passwordController.text.isEmpty) { if (passwordController.text.isEmpty) {
CustomSnackBar.displaySnackBar('Password required'); CustomSnackBar.displaySnackBar('Password required');
return true; return true;
@ -336,20 +401,24 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Password name required'); CustomSnackBar.displaySnackBar('Password name required');
return true; return true;
} }
if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) { if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) {
CustomSnackBar.displaySnackBar('Select effective time'); CustomSnackBar.displaySnackBar('Select effective time');
return true; return true;
} }
if (expirationTime == 'Select Time' || expirationTimeTimeStamp == null) { if (expirationTime == 'Select Time' || expirationTimeTimeStamp == null) {
CustomSnackBar.displaySnackBar('Select expiration time'); CustomSnackBar.displaySnackBar('Select expiration time');
return true; return true;
} }
if (repeat == true && (endTime == null || startTime == null || selectedDays == null)) { if (repeat == true && (endTime == null || startTime == null || selectedDays == null)) {
CustomSnackBar.displaySnackBar('Start Time and End time and the days required '); CustomSnackBar.displaySnackBar('Start Time and End time and the days required ');
return true; return true;
} }
return false; return false;
} }
bool timeLimitValidate() { bool timeLimitValidate() {
if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) { if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) {
@ -392,3 +461,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }

View File

@ -53,6 +53,14 @@ class SelectTimeEvent extends SmartDoorEvent {
List<Object> get props => [context,isEffective]; List<Object> get props => [context,isEffective];
} }
class SelectTimeOnlinePasswordEvent extends SmartDoorEvent {
final BuildContext context;
final bool isEffective;
const SelectTimeOnlinePasswordEvent({required this.context,required this.isEffective});
@override
List<Object> get props => [context,isEffective];
}
class ToggleRepeatEvent extends SmartDoorEvent {} class ToggleRepeatEvent extends SmartDoorEvent {}
class SetStartEndTimeEvent extends SmartDoorEvent { class SetStartEndTimeEvent extends SmartDoorEvent {
final bool val; final bool val;

View File

@ -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<HourPickerDialog> {
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<int>(
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<bool>(
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<TimeOfDay?> showHourPicker({
required BuildContext context,
required TimeOfDay initialTime,
}) {
return showDialog<TimeOfDay>(
context: context,
builder: (context) => HourPickerDialog(initialTime: initialTime),
);
}

View File

@ -60,7 +60,7 @@ class NameTimeWidget extends StatelessWidget {
child: InkWell( child: InkWell(
onTap: () { onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeEvent(context: context, isEffective: true)); BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeOnlinePasswordEvent(context: context, isEffective: true));
}, },
child: Text( child: Text(
BlocProvider.of<SmartDoorBloc>(context).effectiveTime, BlocProvider.of<SmartDoorBloc>(context).effectiveTime,
@ -92,7 +92,7 @@ class NameTimeWidget extends StatelessWidget {
child: InkWell( child: InkWell(
onTap: () { onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add( BlocProvider.of<SmartDoorBloc>(context).add(
SelectTimeEvent( SelectTimeOnlinePasswordEvent(
context: context, isEffective: false)); context: context, isEffective: false));
}, },
child: Text( child: Text(

View File

@ -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/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_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.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/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_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!), create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) { child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
if (state is FailedState) { if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar( CustomSnackBar.displaySnackBar(
SnackBar( state.errorMessage
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
); );
} }
if (state is IsRepeatState){ if (state is IsRepeatState){
@ -104,6 +102,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
Expanded( Expanded(
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
child: BodyLarge( child: BodyLarge(
style: const TextStyle( style: const TextStyle(
@ -114,8 +113,9 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
wordSpacing: 2), wordSpacing: 2),
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: smartDoorBloc.passwordController.text, text: smartDoorBloc.passwordController.text,
fontSize: 25, fontSize: 23,
),), ),),
IconButton( IconButton(
onPressed: () async { onPressed: () async {
await Clipboard.setData(ClipboardData( await Clipboard.setData(ClipboardData(
@ -166,7 +166,6 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
], ],
), ),
], ],
), ),
), ),
@ -195,9 +194,6 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
onPressed: () async { onPressed: () async {
if(generated==false){ if(generated==false){
smartDoorBloc.add(GenerateAndSavePasswordOneTimeEvent(context: context)); smartDoorBloc.add(GenerateAndSavePasswordOneTimeEvent(context: context));
await Clipboard.setData(
ClipboardData(text: smartDoorBloc.passwordController.text)
);
}else{ }else{
if(smartDoorBloc.passwordNameController.text.isNotEmpty){ if(smartDoorBloc.passwordNameController.text.isNotEmpty){
smartDoorBloc.add(RenamePasswordEvent()); smartDoorBloc.add(RenamePasswordEvent());

View File

@ -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/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_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.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/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
@ -27,11 +28,8 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
child: BlocConsumer<SmartDoorBloc, SmartDoorState>( child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) { listener: (context, state) {
if (state is FailedState) { if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar( CustomSnackBar.displaySnackBar(
SnackBar( state.errorMessage
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
); );
} }
if (state is IsRepeatState) { if (state is IsRepeatState) {
@ -240,8 +238,7 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
), ),
const BodyMedium( const BodyMedium(
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: text: 'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.',
'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.',
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor, fontColor: ColorsManager.grayColor,
), ),
@ -259,14 +256,10 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
backgroundColor: ColorsManager.primaryColor, backgroundColor: ColorsManager.primaryColor,
onPressed: () async { onPressed: () async {
if (generated == false) { if (generated == false) {
smartDoorBloc.add( smartDoorBloc.add(GenerateAndSavePasswordTimeLimitEvent(context: context));
GenerateAndSavePasswordTimeLimitEvent(context: context));
await Clipboard.setData(
ClipboardData(text: smartDoorBloc.passwordController.text)
);
} else { } else {
if(smartDoorBloc.passwordNameController.text.isNotEmpty){ if(smartDoorBloc.passwordNameController.text.isNotEmpty){
smartDoorBloc.add(RenamePasswordEvent()); smartDoorBloc.add(RenamePasswordEvent());
} }
Navigator.of(context).pop(true); Navigator.of(context).pop(true);
} }

View File

@ -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/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.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 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'door_dialog.dart'; import 'door_dialog.dart';
@ -22,11 +23,8 @@ class TimeLimitedPasswordPage extends StatelessWidget {
child: BlocConsumer<SmartDoorBloc, SmartDoorState>( child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) { listener: (context, state) {
if (state is FailedState) { if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar( CustomSnackBar.displaySnackBar(
SnackBar( state.errorMessage
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
); );
} }
}, },
@ -40,10 +38,8 @@ class TimeLimitedPasswordPage extends StatelessWidget {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => CreateOfflineTimeLimitPasswordPage(deviceId: deviceId,) MaterialPageRoute(builder: (context) => CreateOfflineTimeLimitPasswordPage(deviceId: deviceId,)
)).then((result) { )).then((result) {
if (result != null) { smartDoorBloc.add(InitialTimeLimitPassword());
smartDoorBloc.add(InitialTimeLimitPassword()); smartDoorBloc.add(InitialTimeLimitPassword());
smartDoorBloc.add(InitialTimeLimitPassword());
}
}); });
}, },
icon: const Icon(Icons.add) icon: const Icon(Icons.add)

View File

@ -197,13 +197,13 @@ class DevicesAPI {
required String invalidTime, required String invalidTime,
required String deviceId, required String deviceId,
List<Schedule>? scheduleList,}) async { List<Schedule>? scheduleList,}) async {
Map<String, dynamic> body = { Map<String, dynamic> body = {
"name": name, "name": name,
"password": password, "password": password,
"effectiveTime": effectiveTime, "effectiveTime": effectiveTime,
"invalidTime": invalidTime, "invalidTime": invalidTime,
}; };
print('createPassword =$body');
if (scheduleList != null) { if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
} }
@ -235,7 +235,7 @@ class DevicesAPI {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: true,
body: { body: {
"effectiveTime": effectiveTime, "effectiveTime": effectiveTime,
"invalidTime": invalidTime "invalidTime": invalidTime