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
@@ -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_event.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_state.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/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/offline_temporary_password.dart';
import 'package:syncrow_app/features/devices/model/smart_door_model.dart'; 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';
@@ -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/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';
class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> { class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
final String deviceId; final String deviceId;
late SmartDoorModel deviceStatus; late SmartDoorModel deviceStatus;
static String pageType = '';
bool isSavingPassword = false; bool isSavingPassword = false;
SmartDoorBloc({required this.deviceId}) : super(InitialState()) { SmartDoorBloc({required this.deviceId}) : super(InitialState()) {
on<InitialEvent>(_fetchSmartDoorStatus); on<InitialEvent>(_fetchSmartDoorStatus);
on<InitialPasswordsPage>(getTemporaryPasswords); on<InitialPasswordsPage>(getTemporaryPasswords);
on<InitialOneTimePassword>(getOneTimePasswords);
on<InitialTimeLimitPassword>(getTimeLimitPasswords);
on<UpdateLockEvent>(_updateLock); on<UpdateLockEvent>(_updateLock);
on<SavePasswordEvent>(savePassword); on<SavePasswordEvent>(savePassword);
on<ToggleRepeatEvent>(toggleRepeat); on<ToggleRepeatEvent>(toggleRepeat);
@@ -49,7 +52,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
DateTime? startTime; DateTime? startTime;
DateTime? endTime; DateTime? endTime;
List<TemporaryPassword>? temporaryPasswords = []; List<TemporaryPassword>? temporaryPasswords = [];
List<TemporaryPassword>? oneTimePasswords = []; List<OfflinePasswordModel>? oneTimePasswords = [];
List<OfflinePasswordModel>? timeLimitPasswords = [];
Future generate7DigitNumber(GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async { Future generate7DigitNumber(GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
@@ -72,8 +76,7 @@ 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;
emit(const GeneratePasswordOneTimestate(generated: true)); emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) { } catch (_) {
emit(FailedState(errorMessage: _.toString())); emit(FailedState(errorMessage: _.toString()));
}finally { }finally {
@@ -100,9 +103,12 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
void _renamePassword(RenamePasswordEvent event, Emitter<SmartDoorState> emit) async { void _renamePassword(RenamePasswordEvent event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
print('==4444${passwordNameController.text}');
print('==1==${deviceId}');
print('==4444${passwordId}');
var response = await DevicesAPI.renamePass( var response = await DevicesAPI.renamePass(
name:passwordNameController.text , name:passwordNameController.text ,
deviceId:deviceId , doorLockUuid:deviceId ,
passwordId:passwordId passwordId:passwordId
); );
emit(UpdateState(smartDoorModel: deviceStatus)); emit(UpdateState(smartDoorModel: deviceStatus));
@@ -115,14 +121,37 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
void getTemporaryPasswords(InitialPasswordsPage event, Emitter<SmartDoorState> emit) async { void getTemporaryPasswords(InitialPasswordsPage event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
print('deviceId=$deviceId'); var response = await DevicesAPI.getTemporaryPasswords(deviceId, );
pageType = event.type!;
var response = await DevicesAPI.getTemporaryPasswords(deviceId, pageType);
if (response is List) { if (response is List) {
temporaryPasswords = response.map((item) => TemporaryPassword.fromJson(item)).toList(); temporaryPasswords = response.map((item) => TemporaryPassword.fromJson(item)).toList();
} else if (response is Map && response.containsKey('data')) { } else if (response is Map && response.containsKey('data')) {
temporaryPasswords = temporaryPasswords = (response['data'] as List).map((item) => TemporaryPassword.fromJson(item)).toList();
(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!)); emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) { } catch (e) {
@@ -166,8 +195,6 @@ 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> selectTime(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState()); emit(ChangeTimeState());
final DateTime? picked = await showDatePicker( final DateTime? picked = await showDatePicker(
@@ -241,7 +268,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
isSavingPassword = true; isSavingPassword = true;
emit(LoadingSaveState()); emit(LoadingSaveState());
var res = await DevicesAPI.createPassword( var res = await DevicesAPI.createPassword(
pageType: pageType,
deviceId: deviceId, deviceId: deviceId,
effectiveTime: effectiveTimeTimeStamp.toString(), effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString(), invalidTime: expirationTimeTimeStamp.toString(),
@@ -267,7 +293,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
Future<void> generateAndSavePasswordTimeLimited (GenerateAndSavePasswordTimeLimitEvent event, Emitter<SmartDoorState> emit) async { Future<void> generateAndSavePasswordTimeLimited (GenerateAndSavePasswordTimeLimitEvent event, Emitter<SmartDoorState> emit) async {
if (_validateInputs() || isSavingPassword) return; if (timeLimitValidate() || isSavingPassword) return;
try { try {
isSavingPassword = true; isSavingPassword = true;
emit(LoadingInitialState()); emit(LoadingInitialState());
@@ -280,22 +306,20 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Save Successfully'); CustomSnackBar.displaySnackBar('Save Successfully');
emit(const GeneratePasswordOneTimestate(generated: true)); emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) { } catch (_) {
print(_); emit(FailedState(errorMessage: e.toString()));
} }
finally { finally {
isSavingPassword = false; isSavingPassword = false;
} }
} }
Future<void> deletePassword(DeletePasswordEvent event, Emitter<SmartDoorState> emit) async { Future<void> deletePassword(DeletePasswordEvent event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
var response = var response =
await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId) await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId)
.then((value) async { .then((value) async {
add(InitialPasswordsPage(type: pageType)); add(InitialPasswordsPage());
}); });
} catch (e) { } catch (e) {
emit(FailedState(errorMessage: e.toString())); emit(FailedState(errorMessage: e.toString()));
@@ -303,15 +327,15 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
bool _validateInputs() { bool _validateInputs() {
if (passwordController.text.length < 7 && pageType=='Online Password') { if (passwordController.text.length < 7 ) {
CustomSnackBar.displaySnackBar('Password less than 7'); CustomSnackBar.displaySnackBar('Password less than 7');
return true; return true;
} }
if (passwordController.text.isEmpty && pageType=='Online Password') { if (passwordController.text.isEmpty) {
CustomSnackBar.displaySnackBar('Password required'); CustomSnackBar.displaySnackBar('Password required');
return true; return true;
} }
if (passwordNameController.text.isEmpty && pageType=='Online Password') { if (passwordNameController.text.isEmpty ) {
CustomSnackBar.displaySnackBar('Password name required'); CustomSnackBar.displaySnackBar('Password name required');
return true; return true;
} }
@@ -329,7 +353,18 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
return false; 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 = [ List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"}, {"day": "Sun", "key": "Sun"},
@@ -352,6 +387,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
emit(ChangeTimeState()); emit(ChangeTimeState());
} }
String getTimeOnly(DateTime? dateTime) { String getTimeOnly(DateTime? dateTime) {
if (dateTime == null) return ''; if (dateTime == null) return '';
return DateFormat('HH:mm').format(dateTime); return DateFormat('HH:mm').format(dateTime);
@@ -9,11 +9,9 @@ abstract class SmartDoorEvent extends Equatable {
} }
class InitialEvent extends SmartDoorEvent {} class InitialEvent extends SmartDoorEvent {}
class InitialPasswordsPage extends SmartDoorEvent { class InitialPasswordsPage extends SmartDoorEvent {}
final String? type;
const InitialPasswordsPage({ this.type});
}
class InitialOneTimePassword extends SmartDoorEvent {} class InitialOneTimePassword extends SmartDoorEvent {}
class InitialTimeLimitPassword extends SmartDoorEvent {}
class UpdateLockEvent extends SmartDoorEvent { class UpdateLockEvent extends SmartDoorEvent {
final bool value; final bool value;
@@ -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,
};
}
}
@@ -1,6 +1,4 @@
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/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_button.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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/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_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/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';
class OfflineOneTimePasswordPage extends StatelessWidget { class OfflineOneTimePasswordPage extends StatelessWidget {
final String? deviceId; final String? deviceId;
final String? type; final String? type;
@@ -102,8 +100,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
color: Colors.black, color: Colors.black,
), ),
); );
}) }) :[
:[
Expanded( Expanded(
child: Row( child: Row(
children: [ children: [
@@ -158,8 +155,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width / 2.6, width: MediaQuery.of(context).size.width / 2.6,
child: TextFormField( child: TextFormField(
controller: BlocProvider.of<SmartDoorBloc>(context) controller: BlocProvider.of<SmartDoorBloc>(context).passwordNameController,
.passwordNameController,
decoration: const InputDecoration( decoration: const InputDecoration(
hintText: 'Enter The Name', hintText: 'Enter The Name',
hintStyle: TextStyle( hintStyle: TextStyle(
@@ -191,22 +187,26 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
Center( Center(
child: SizedBox( child: SizedBox(
width: MediaQuery.of(context).size.width/1.5, width: MediaQuery.of(context).size.width/1.5,
child: DefaultButton( child: DoorLockButton(
isDone: generated, isDone: generated,
isLoading: smartDoorBloc.isSavingPassword , isLoading: smartDoorBloc.isSavingPassword ,
borderRadius: 30, borderRadius: 30,
backgroundColor:ColorsManager.primaryColor , backgroundColor:ColorsManager.primaryColor ,
onPressed: () { 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());
} }
Navigator.pop(context); Navigator.of(context).pop(true);
} }
}, },
child: const BodyMedium( child: const BodyMedium(
text: 'Obtain Password', text: 'Obtain Password',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontColor: Colors.white, fontColor: Colors.white,
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.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/devices/model/temporary_password_model.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/context_extension.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'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class DoorDialog extends StatefulWidget { class DoorDialog extends StatefulWidget {
final String title; final String? title;
final TemporaryPassword value; final TemporaryPassword? temporaryPassword;
final OfflinePasswordModel? offline;
const DoorDialog({ const DoorDialog({
super.key, super.key,
required this.title, this.title,
required this.value, this.offline,
this.temporaryPassword,
}); });
@override @override
@@ -28,16 +31,18 @@ class DoorDialogState extends State<DoorDialog> {
@override @override
Widget build(BuildContext context) { 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 = 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 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 = 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 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( return Dialog(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -49,7 +54,7 @@ class DoorDialogState extends State<DoorDialog> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
BodyMedium( BodyMedium(
text: widget.title, text: widget.title ?? '',
style: context.bodyMedium.copyWith( style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity, color: ColorsManager.primaryColorWithOpacity,
fontWeight: FontsManager.extraBold, fontWeight: FontsManager.extraBold,
@@ -111,7 +116,8 @@ class DoorDialogState extends State<DoorDialog> {
width: double.infinity, width: double.infinity,
color: ColorsManager.greyColor, color: ColorsManager.greyColor,
), ),
Row( widget.temporaryPassword?.effectiveTime!=null?
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
InkWell( InkWell(
@@ -130,7 +136,7 @@ class DoorDialogState extends State<DoorDialog> {
width: 1, width: 1,
color: ColorsManager.greyColor, color: ColorsManager.greyColor,
), ),
InkWell( InkWell(
onTap: () { onTap: () {
Navigator.pop(context, 'delete'); 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),
),
),
),
),
],
) )
], ],
), ),
@@ -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_button.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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/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_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/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';
class OfflineTimeLimitPasswordPage extends StatelessWidget { class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
final String? deviceId; final String? deviceId;
final String? type; final String? type;
const OfflineTimeLimitPasswordPage({super.key, this.deviceId, this.type}); const CreateOfflineTimeLimitPasswordPage({super.key, this.deviceId, this.type});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
bool isRepeat = false; bool isRepeat = false;
@@ -253,21 +254,23 @@ class OfflineTimeLimitPasswordPage extends StatelessWidget {
Center( Center(
child: SizedBox( child: SizedBox(
width: MediaQuery.of(context).size.width / 1.5, width: MediaQuery.of(context).size.width / 1.5,
child: DefaultButton( child: DoorLockButton(
isDone: generated, isDone: generated,
isLoading: smartDoorBloc.isSavingPassword, isLoading: smartDoorBloc.isSavingPassword,
borderRadius: 30, borderRadius: 30,
backgroundColor: ColorsManager.primaryColor, backgroundColor: ColorsManager.primaryColor,
onPressed: () { onPressed: () async {
if (generated == false) { if (generated == false) {
smartDoorBloc.add( smartDoorBloc.add(
GenerateAndSavePasswordTimeLimitEvent( GenerateAndSavePasswordTimeLimitEvent(context: context));
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.pop(context); Navigator.of(context).pop(true);
} }
}, },
child: const BodyMedium( child: const BodyMedium(
@@ -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')
],
),
);
},
));
})
);
}
}
@@ -1,6 +1,8 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.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/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_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
@@ -90,7 +92,7 @@ class TemporaryPasswordPage extends StatelessWidget {
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
), ),
onTap: () { 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( trailing: const Icon(
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
@@ -108,7 +110,7 @@ class TemporaryPasswordPage extends StatelessWidget {
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
), ),
onTap: () { 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( trailing: const Icon(
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
@@ -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')
],
),
);
},
));
})
);
}
}
@@ -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_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_event.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_state.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_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';
@@ -22,7 +20,7 @@ class ViewTemporaryPassword extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialPasswordsPage(type:type )), create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialPasswordsPage( )),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>( child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) { listener: (context, state) {
if (state is FailedState) { if (state is FailedState) {
@@ -43,15 +41,10 @@ class ViewTemporaryPassword extends StatelessWidget {
onPressed: () { onPressed: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute(builder: (context) => MaterialPageRoute(builder: (context) =>
type=='One-Time' ? CreateTemporaryPassword(deviceId: deviceId, type: type))).then((result) {
OfflineOneTimePasswordPage(deviceId: deviceId, type: type)
: type=='Time-Limited' ?
OfflineTimeLimitPasswordPage(deviceId: deviceId, type: type)
:
CreateTemporaryPassword(deviceId: deviceId, type: type),
)).then((result) {
if (result != null && 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) { builder: (context) {
return DoorDialog( return DoorDialog(
title: 'Password Information', title: 'Password Information',
value: smartDoorBloc.temporaryPasswords![index], temporaryPassword: smartDoorBloc.temporaryPasswords![index],
); );
}, },
); );
@@ -29,7 +29,6 @@ class DefaultButton extends StatelessWidget {
final double? padding; final double? padding;
final bool isDone; final bool isDone;
final bool isLoading; final bool isLoading;
final TextStyle? customTextStyle; final TextStyle? customTextStyle;
final ButtonStyle? customButtonStyle; final ButtonStyle? customButtonStyle;
@@ -91,12 +90,14 @@ class DefaultButton extends StatelessWidget {
color: Colors.white, color: Colors.white,
), ),
) )
: isDone :
? const Icon(
Icons.check_circle_outline,
color: Colors.white, isDone
) ? const Icon(
: child, Icons.check_circle_outline,
color: Colors.white,
) :child ,
), ),
), ),
); );
@@ -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 ,
),
),
);
}
}
+1 -1
View File
@@ -153,5 +153,5 @@ abstract class ApiEndpoints {
//multiple-time offline //multiple-time offline
static const String deleteTemporaryPassword = static const String deleteTemporaryPassword =
'$baseUrl/door-lock/temporary-password/{doorLockUuid}/{passwordId}'; '$baseUrl/door-lock/temporary-password/online/{doorLockUuid}/{passwordId}';
} }
+39 -19
View File
@@ -1,4 +1,5 @@
import 'dart:async'; 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_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
@@ -72,10 +73,12 @@ class DevicesAPI {
static Future<Map<String, dynamic>> renamePass({ static Future<Map<String, dynamic>> renamePass({
required String name, required String name,
required String deviceId, required String doorLockUuid,
required String passwordId}) async { required String passwordId}) async {
final response = await _httpService.put( final response = await _httpService.put(
path: ApiEndpoints.renamePassword.replaceAll('{deviceUuid}', deviceId).replaceAll('{passwordId}', passwordId), path: ApiEndpoints.renamePassword
.replaceAll('{doorLockUuid}', doorLockUuid)
.replaceAll('{passwordId}', passwordId),
body: { body: {
"name": name "name": name
}, },
@@ -155,10 +158,9 @@ class DevicesAPI {
return response; return response;
} }
static Future getTemporaryPasswords(String deviceId, pageType) async { static Future getTemporaryPasswords(String deviceId, ) async {
final response = await _httpService.get( final response = await _httpService.get(
path: path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@@ -167,35 +169,50 @@ class DevicesAPI {
return response; 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({ static Future createPassword({
required String name, required String name,
required String password, required String password,
required String effectiveTime, required String effectiveTime,
required String invalidTime, required String invalidTime,
required String deviceId, required String deviceId,
required String pageType, List<Schedule>? scheduleList,}) async {
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);
}
Map<String, dynamic> body = { Map<String, dynamic> body = {
"name": name, "name": name,
"password": password, "password": password,
"effectiveTime": effectiveTime, "effectiveTime": effectiveTime,
"invalidTime": invalidTime, "invalidTime": invalidTime,
}; };
if (pageType == 'Online Password' && scheduleList != null) { if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
} }
final response = await _httpService.post( final response = await _httpService.post(
path: endpointPath, path: ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
body: body, body: body,
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => json, expectedResponseModel: (json) => json,
@@ -209,6 +226,7 @@ class DevicesAPI {
path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
print('generateOneTimePassword=${json}');
return json; return json;
}, },
); );
@@ -250,4 +268,6 @@ class DevicesAPI {
); );
return response; return response;
} }
} }