door lock

This commit is contained in:
mohammad
2024-08-04 16:45:07 +03:00
parent b6053e1ceb
commit 9c838ed079
14 changed files with 557 additions and 95 deletions

View File

@ -6,6 +6,7 @@ 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_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/offline_password_model.dart';
import 'package:syncrow_app/features/devices/model/offline_temporary_password.dart';
import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
@ -14,15 +15,17 @@ import 'package:syncrow_app/features/devices/model/temporary_password_model.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';
class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
final String deviceId;
late SmartDoorModel deviceStatus;
static String pageType = '';
bool isSavingPassword = false;
SmartDoorBloc({required this.deviceId}) : super(InitialState()) {
on<InitialEvent>(_fetchSmartDoorStatus);
on<InitialPasswordsPage>(getTemporaryPasswords);
on<InitialOneTimePassword>(getOneTimePasswords);
on<InitialTimeLimitPassword>(getTimeLimitPasswords);
on<UpdateLockEvent>(_updateLock);
on<SavePasswordEvent>(savePassword);
on<ToggleRepeatEvent>(toggleRepeat);
@ -49,7 +52,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
DateTime? startTime;
DateTime? endTime;
List<TemporaryPassword>? temporaryPasswords = [];
List<TemporaryPassword>? oneTimePasswords = [];
List<OfflinePasswordModel>? oneTimePasswords = [];
List<OfflinePasswordModel>? timeLimitPasswords = [];
Future generate7DigitNumber(GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(LoadingInitialState());
@ -72,8 +76,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
ApiResponse pass= ApiResponse.fromJson(res);
passwordController.text =pass.data.offlineTempPassword;
passwordId=pass.data.offlineTempPasswordId;
emit(const GeneratePasswordOneTimestate(generated: true));
emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) {
emit(FailedState(errorMessage: _.toString()));
}finally {
@ -100,9 +103,12 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
void _renamePassword(RenamePasswordEvent event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
print('==4444${passwordNameController.text}');
print('==1==${deviceId}');
print('==4444${passwordId}');
var response = await DevicesAPI.renamePass(
name:passwordNameController.text ,
deviceId:deviceId ,
doorLockUuid:deviceId ,
passwordId:passwordId
);
emit(UpdateState(smartDoorModel: deviceStatus));
@ -115,14 +121,37 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
void getTemporaryPasswords(InitialPasswordsPage event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
print('deviceId=$deviceId');
pageType = event.type!;
var response = await DevicesAPI.getTemporaryPasswords(deviceId, pageType);
var response = await DevicesAPI.getTemporaryPasswords(deviceId, );
if (response is List) {
temporaryPasswords = response.map((item) => TemporaryPassword.fromJson(item)).toList();
} else if (response is Map && response.containsKey('data')) {
temporaryPasswords =
(response['data'] as List).map((item) => TemporaryPassword.fromJson(item)).toList();
temporaryPasswords = (response['data'] as List).map((item) => TemporaryPassword.fromJson(item)).toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
}
}
void getOneTimePasswords(InitialOneTimePassword event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getOneTimePasswords(deviceId);
if (response is List) {
oneTimePasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
}
}
void getTimeLimitPasswords(InitialTimeLimitPassword event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getTimeLimitPasswords(deviceId);
if (response is List) {
timeLimitPasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) {
@ -166,8 +195,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
emit(UpdateState(smartDoorModel: deviceStatus));
}
Future<void> selectTime(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
@ -241,7 +268,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
isSavingPassword = true;
emit(LoadingSaveState());
var res = await DevicesAPI.createPassword(
pageType: pageType,
deviceId: deviceId,
effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString(),
@ -267,7 +293,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
Future<void> generateAndSavePasswordTimeLimited (GenerateAndSavePasswordTimeLimitEvent event, Emitter<SmartDoorState> emit) async {
if (_validateInputs() || isSavingPassword) return;
if (timeLimitValidate() || isSavingPassword) return;
try {
isSavingPassword = true;
emit(LoadingInitialState());
@ -280,22 +306,20 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Save Successfully');
emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) {
print(_);
emit(FailedState(errorMessage: e.toString()));
}
finally {
isSavingPassword = false;
}
}
Future<void> deletePassword(DeletePasswordEvent event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response =
await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId)
.then((value) async {
add(InitialPasswordsPage(type: pageType));
add(InitialPasswordsPage());
});
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
@ -303,15 +327,15 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
bool _validateInputs() {
if (passwordController.text.length < 7 && pageType=='Online Password') {
if (passwordController.text.length < 7 ) {
CustomSnackBar.displaySnackBar('Password less than 7');
return true;
}
if (passwordController.text.isEmpty && pageType=='Online Password') {
if (passwordController.text.isEmpty) {
CustomSnackBar.displaySnackBar('Password required');
return true;
}
if (passwordNameController.text.isEmpty && pageType=='Online Password') {
if (passwordNameController.text.isEmpty ) {
CustomSnackBar.displaySnackBar('Password name required');
return true;
}
@ -329,7 +353,18 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
return false;
}
bool timeLimitValidate() {
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;
}
return false;
}
List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"},
@ -352,6 +387,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
emit(ChangeTimeState());
}
String getTimeOnly(DateTime? dateTime) {
if (dateTime == null) return '';
return DateFormat('HH:mm').format(dateTime);

View File

@ -9,11 +9,9 @@ abstract class SmartDoorEvent extends Equatable {
}
class InitialEvent extends SmartDoorEvent {}
class InitialPasswordsPage extends SmartDoorEvent {
final String? type;
const InitialPasswordsPage({ this.type});
}
class InitialPasswordsPage extends SmartDoorEvent {}
class InitialOneTimePassword extends SmartDoorEvent {}
class InitialTimeLimitPassword extends SmartDoorEvent {}
class UpdateLockEvent extends SmartDoorEvent {
final bool value;

View File

@ -0,0 +1,63 @@
class OfflinePasswordModel {
final dynamic gmtCreate;
final dynamic gmtExpired;
final dynamic gmtStart;
final bool hasClearPwd;
final String optUid;
final String pwd;
final dynamic pwdId;
final String pwdName;
final String pwdTypeCode;
final String revokedPwdName;
final dynamic status;
OfflinePasswordModel({
required this.gmtCreate,
required this.gmtExpired,
required this.gmtStart,
required this.hasClearPwd,
required this.optUid,
required this.pwd,
required this.pwdId,
required this.pwdName,
required this.pwdTypeCode,
required this.revokedPwdName,
required this.status,
});
// Factory method to create a Password from a JSON map
factory OfflinePasswordModel.fromJson(Map<String, dynamic> json) {
return OfflinePasswordModel(
gmtCreate: json['gmtCreate'],
gmtExpired: json['gmtExpired'],
gmtStart: json['gmtStart'],
hasClearPwd: json['hasClearPwd'],
optUid: json['optUid'],
pwd: json['pwd'],
pwdId: json['pwdId'],
pwdName: json['pwdName'],
pwdTypeCode: json['pwdTypeCode'],
revokedPwdName: json['revokedPwdName'],
status: json['status'],
);
}
// Method to convert a Password object to a JSON map
Map<String, dynamic> toJson() {
return {
'gmtCreate': gmtCreate,
'gmtExpired': gmtExpired,
'gmtStart': gmtStart,
'hasClearPwd': hasClearPwd,
'optUid': optUid,
'pwd': pwd,
'pwdId': pwdId,
'pwdName': pwdName,
'pwdTypeCode': pwdTypeCode,
'revokedPwdName': revokedPwdName,
'status': status,
};
}
}

View File

@ -1,6 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -12,12 +10,12 @@ import 'package:syncrow_app/features/devices/view/widgets/smart_door/repeat_widg
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
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/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/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class OfflineOneTimePasswordPage extends StatelessWidget {
final String? deviceId;
final String? type;
@ -102,8 +100,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
color: Colors.black,
),
);
})
:[
}) :[
Expanded(
child: Row(
children: [
@ -158,8 +155,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
SizedBox(
width: MediaQuery.of(context).size.width / 2.6,
child: TextFormField(
controller: BlocProvider.of<SmartDoorBloc>(context)
.passwordNameController,
controller: BlocProvider.of<SmartDoorBloc>(context).passwordNameController,
decoration: const InputDecoration(
hintText: 'Enter The Name',
hintStyle: TextStyle(
@ -191,22 +187,26 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width/1.5,
child: DefaultButton(
child: DoorLockButton(
isDone: generated,
isLoading: smartDoorBloc.isSavingPassword ,
borderRadius: 30,
backgroundColor:ColorsManager.primaryColor ,
onPressed: () {
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());
}
Navigator.pop(context);
Navigator.of(context).pop(true);
}
},
child: const BodyMedium(
text: 'Obtain Password',
fontWeight: FontWeight.bold,
fontColor: Colors.white,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/model/offline_password_model.dart';
import 'package:syncrow_app/features/devices/model/temporary_password_model.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
@ -7,13 +8,15 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class DoorDialog extends StatefulWidget {
final String title;
final TemporaryPassword value;
final String? title;
final TemporaryPassword? temporaryPassword;
final OfflinePasswordModel? offline;
const DoorDialog({
super.key,
required this.title,
required this.value,
this.title,
this.offline,
this.temporaryPassword,
});
@override
@ -28,16 +31,18 @@ class DoorDialogState extends State<DoorDialog> {
@override
Widget build(BuildContext context) {
final effectiveTime = widget.temporaryPassword?.effectiveTime ??int.parse( widget.offline?.gmtStart);
final invalidTime = widget.temporaryPassword?.invalidTime ?? int.parse(widget.offline?.gmtExpired);
final DateTime effectiveDateTime =
DateTime.fromMillisecondsSinceEpoch(widget.value.effectiveTime * 1000, isUtc: false);
DateTime.fromMillisecondsSinceEpoch(effectiveTime! * 1000, isUtc: false);
String formattedDateEffectiveTime = DateFormat('yyyy-MM-dd').format(effectiveDateTime);
String formattedTimeEffectiveTime = DateFormat('HH:mm:ss').format(effectiveDateTime);
String formattedTimeEffectiveTime = DateFormat('hh:mm a').format(effectiveDateTime);
final DateTime expiredDateTime =
DateTime.fromMillisecondsSinceEpoch(widget.value.invalidTime * 1000, isUtc: false);
DateTime.fromMillisecondsSinceEpoch(invalidTime! * 1000, isUtc: false);
String formattedDateExpiredDateTime = DateFormat('yyyy-MM-dd').format(expiredDateTime);
String formattedTimeExpiredDateTime = DateFormat('HH:mm:ss').format(expiredDateTime);
String formattedTimeExpiredDateTime = DateFormat('hh:mm a').format(expiredDateTime);
return Dialog(
child: Container(
decoration: BoxDecoration(
@ -49,7 +54,7 @@ class DoorDialogState extends State<DoorDialog> {
mainAxisSize: MainAxisSize.min,
children: [
BodyMedium(
text: widget.title,
text: widget.title ?? '',
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontWeight: FontsManager.extraBold,
@ -111,7 +116,8 @@ class DoorDialogState extends State<DoorDialog> {
width: double.infinity,
color: ColorsManager.greyColor,
),
Row(
widget.temporaryPassword?.effectiveTime!=null?
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
InkWell(
@ -130,7 +136,7 @@ class DoorDialogState extends State<DoorDialog> {
width: 1,
color: ColorsManager.greyColor,
),
InkWell(
InkWell(
onTap: () {
Navigator.pop(context, 'delete');
},
@ -142,6 +148,27 @@ class DoorDialogState extends State<DoorDialog> {
),
),
],
):
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
height: 50,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Center(
child: BodyMedium(
text: 'Cancel',
style: context.bodyMedium.copyWith(color: ColorsManager.greyColor),
),
),
),
),
],
)
],
),

View File

@ -9,15 +9,16 @@ import 'package:syncrow_app/features/devices/view/widgets/smart_door/repeat_widg
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
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/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/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class OfflineTimeLimitPasswordPage extends StatelessWidget {
class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
final String? deviceId;
final String? type;
const OfflineTimeLimitPasswordPage({super.key, this.deviceId, this.type});
const CreateOfflineTimeLimitPasswordPage({super.key, this.deviceId, this.type});
@override
Widget build(BuildContext context) {
bool isRepeat = false;
@ -253,21 +254,23 @@ class OfflineTimeLimitPasswordPage extends StatelessWidget {
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width / 1.5,
child: DefaultButton(
child: DoorLockButton(
isDone: generated,
isLoading: smartDoorBloc.isSavingPassword,
borderRadius: 30,
backgroundColor: ColorsManager.primaryColor,
onPressed: () {
onPressed: () async {
if (generated == false) {
smartDoorBloc.add(
GenerateAndSavePasswordTimeLimitEvent(
context: context));
GenerateAndSavePasswordTimeLimitEvent(context: context));
await Clipboard.setData(
ClipboardData(text: smartDoorBloc.passwordController.text)
);
} else {
if(smartDoorBloc.passwordNameController.text.isNotEmpty){
smartDoorBloc.add(RenamePasswordEvent());
}
Navigator.pop(context);
Navigator.of(context).pop(true);
}
},
child: const BodyMedium(

View File

@ -0,0 +1,111 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_bloc.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_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/offline_one_time_password_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_dialog.dart';
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/resource_manager/color_manager.dart';
class OnetimePasswordPage extends StatelessWidget {
final String? deviceId;
const OnetimePasswordPage({super.key, this.deviceId,});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialOneTimePassword( )),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
);
}
},
builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
title: 'Passwords',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => OfflineOneTimePasswordPage(deviceId: deviceId, )
)).then((result) {
if(result!=null){
smartDoorBloc.add(InitialOneTimePassword());
smartDoorBloc.add(InitialOneTimePassword());
}
});
},
icon: const Icon(Icons.add)
)
],
child: Builder(
builder: (context) {
return state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Center(
child: smartDoorBloc.oneTimePasswords!.isNotEmpty
? ListView.builder(
itemCount: smartDoorBloc.oneTimePasswords!.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon),
title: BodyMedium(
text: 'Password Name: ${smartDoorBloc.oneTimePasswords![index].pwdName}',
fontWeight: FontWeight.normal,
),
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return DoorDialog(
title: 'Password Information',
offline: smartDoorBloc.oneTimePasswords![index],
);
},
);
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
),
);
},
) : Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.noValidPasswords),
const SizedBox(
height: 10,
),
const BodyMedium(text: 'No Valid Passwords')
],
),
);
},
));
})
);
}
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/onetime_password_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/timelimited_password_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/view_temporary_password.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
@ -90,7 +92,7 @@ class TemporaryPasswordPage extends StatelessWidget {
fontWeight: FontWeight.normal,
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ViewTemporaryPassword(deviceId:deviceId,type:'One-Time'),));
Navigator.of(context).push(MaterialPageRoute(builder: (context) => OnetimePasswordPage(deviceId:deviceId,),));
},
trailing: const Icon(
Icons.arrow_forward_ios,
@ -108,7 +110,7 @@ class TemporaryPasswordPage extends StatelessWidget {
fontWeight: FontWeight.normal,
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ViewTemporaryPassword(deviceId:deviceId,type:'Time-Limited'),));
Navigator.of(context).push(MaterialPageRoute(builder: (context) => TimeLimitedPasswordPage(deviceId:deviceId,),));
},
trailing: const Icon(
Icons.arrow_forward_ios,

View File

@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_bloc.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_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/offline_timeLimit_password_page.dart';
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/resource_manager/color_manager.dart';
import 'door_dialog.dart';
class TimeLimitedPasswordPage extends StatelessWidget {
final String? deviceId;
const TimeLimitedPasswordPage({super.key, this.deviceId});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialTimeLimitPassword()),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
);
}
},
builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
title: 'Passwords',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => CreateOfflineTimeLimitPasswordPage(deviceId: deviceId,)
)).then((result) {
if (result != null) {
smartDoorBloc.add(InitialTimeLimitPassword());
smartDoorBloc.add(InitialTimeLimitPassword());
}
});
},
icon: const Icon(Icons.add)
)
],
child: Builder(
builder: (context) {
return state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Center(
child: smartDoorBloc.timeLimitPasswords!.isNotEmpty
? ListView.builder(
itemCount: smartDoorBloc.timeLimitPasswords!.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon),
title: BodyMedium(
text: 'Password Name: ${smartDoorBloc.timeLimitPasswords![index].pwdName}',
fontWeight: FontWeight.normal,
),
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return DoorDialog(
title: 'Password Information',
offline: smartDoorBloc.timeLimitPasswords![index],
);
},
);
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
),
);
},
) : Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.noValidPasswords),
const SizedBox(
height: 10,
),
const BodyMedium(text: 'No Valid Passwords')
],
),
);
},
));
})
);
}
}

View File

@ -4,8 +4,6 @@ import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_bloc.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_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/offline_one_time_password_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/offline_timeLimit_password_page.dart';
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';
@ -22,7 +20,7 @@ class ViewTemporaryPassword extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialPasswordsPage(type:type )),
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialPasswordsPage( )),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
@ -43,15 +41,10 @@ class ViewTemporaryPassword extends StatelessWidget {
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) =>
type=='One-Time' ?
OfflineOneTimePasswordPage(deviceId: deviceId, type: type)
: type=='Time-Limited' ?
OfflineTimeLimitPasswordPage(deviceId: deviceId, type: type)
:
CreateTemporaryPassword(deviceId: deviceId, type: type),
)).then((result) {
CreateTemporaryPassword(deviceId: deviceId, type: type))).then((result) {
if (result != null && result) {
smartDoorBloc.add(InitialPasswordsPage(type:type ));
smartDoorBloc.add(InitialPasswordsPage());
smartDoorBloc.add(InitialPasswordsPage());
}
});
},
@ -85,7 +78,7 @@ class ViewTemporaryPassword extends StatelessWidget {
builder: (context) {
return DoorDialog(
title: 'Password Information',
value: smartDoorBloc.temporaryPasswords![index],
temporaryPassword: smartDoorBloc.temporaryPasswords![index],
);
},
);

View File

@ -29,7 +29,6 @@ class DefaultButton extends StatelessWidget {
final double? padding;
final bool isDone;
final bool isLoading;
final TextStyle? customTextStyle;
final ButtonStyle? customButtonStyle;
@ -91,12 +90,14 @@ class DefaultButton extends StatelessWidget {
color: Colors.white,
),
)
: isDone
? const Icon(
Icons.check_circle_outline,
color: Colors.white,
)
: child,
:
isDone
? const Icon(
Icons.check_circle_outline,
color: Colors.white,
) :child ,
),
),
);

View File

@ -0,0 +1,99 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class DoorLockButton extends StatelessWidget {
const DoorLockButton({
super.key,
this.enabled = true,
this.onPressed,
required this.child,
this.isSecondary = false,
this.isLoading = false,
this.isDone = false,
this.customTextStyle,
this.customButtonStyle,
this.backgroundColor,
this.foregroundColor,
this.borderRadius,
this.height,
this.padding,
});
final void Function()? onPressed;
final Widget child;
final double? height;
final bool isSecondary;
final double? borderRadius;
final bool enabled;
final double? padding;
final bool isDone;
final bool isLoading;
final TextStyle? customTextStyle;
final ButtonStyle? customButtonStyle;
final Color? backgroundColor;
final Color? foregroundColor;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: enabled ? onPressed : null,
style: isSecondary
? null
: customButtonStyle ??
ButtonStyle(
textStyle: MaterialStateProperty.all(
customTextStyle ??
context.bodyMedium.copyWith(
fontSize: 16,
color: foregroundColor,
),
),
foregroundColor: MaterialStateProperty.all(
isSecondary
? Colors.black
: enabled
? foregroundColor ?? Colors.white
: Colors.black,
),
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
return enabled
? backgroundColor ?? ColorsManager.primaryColor
: Colors.grey;
}),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius ?? 20),
),
),
fixedSize: MaterialStateProperty.all(
const Size.fromHeight(50),
),
padding: MaterialStateProperty.all(
EdgeInsets.all(padding ?? 10),
),
minimumSize: MaterialStateProperty.all(
const Size.fromHeight(50),
),
),
child: SizedBox(
height: height ?? 50,
child: Center(
child: isLoading
? const SizedBox.square(
dimension: 24,
child: CircularProgressIndicator(
color: Colors.white,
),
)
: isDone
? const Text('Done') :child ,
),
),
);
}
}

View File

@ -153,5 +153,5 @@ abstract class ApiEndpoints {
//multiple-time offline
static const String deleteTemporaryPassword =
'$baseUrl/door-lock/temporary-password/{doorLockUuid}/{passwordId}';
'$baseUrl/door-lock/temporary-password/online/{doorLockUuid}/{passwordId}';
}

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:developer';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
@ -72,10 +73,12 @@ class DevicesAPI {
static Future<Map<String, dynamic>> renamePass({
required String name,
required String deviceId,
required String doorLockUuid,
required String passwordId}) async {
final response = await _httpService.put(
path: ApiEndpoints.renamePassword.replaceAll('{deviceUuid}', deviceId).replaceAll('{passwordId}', passwordId),
path: ApiEndpoints.renamePassword
.replaceAll('{doorLockUuid}', doorLockUuid)
.replaceAll('{passwordId}', passwordId),
body: {
"name": name
},
@ -155,10 +158,9 @@ class DevicesAPI {
return response;
}
static Future getTemporaryPasswords(String deviceId, pageType) async {
static Future getTemporaryPasswords(String deviceId, ) async {
final response = await _httpService.get(
path:
ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
@ -167,35 +169,50 @@ class DevicesAPI {
return response;
}
//create password
static Future getOneTimePasswords(String deviceId) async {
final response = await _httpService.get(
path: ApiEndpoints.getOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
log('==============$json');
return json;
},
);
return response;
}
static Future getTimeLimitPasswords(String deviceId) async {
final response = await _httpService.get(
path: ApiEndpoints.getMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
print('00000000$json');
return json;
},
);
return response;
}
//create password
static Future createPassword({
required String name,
required String password,
required String effectiveTime,
required String invalidTime,
required String deviceId,
required String pageType,
List<Schedule>? scheduleList,
}) async {
String endpointPath;
if (pageType == 'Online Password') {
endpointPath = ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId);
} else if (pageType == 'One-Time') {
endpointPath = ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId);
} else {
endpointPath = ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId);
}
List<Schedule>? scheduleList,}) async {
Map<String, dynamic> body = {
"name": name,
"password": password,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime,
};
if (pageType == 'Online Password' && scheduleList != null) {
if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
}
final response = await _httpService.post(
path: endpointPath,
path: ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
body: body,
showServerMessage: false,
expectedResponseModel: (json) => json,
@ -209,6 +226,7 @@ class DevicesAPI {
path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
print('generateOneTimePassword=${json}');
return json;
},
);
@ -250,4 +268,6 @@ class DevicesAPI {
);
return response;
}
}