Merge branch 'dev' into doorlock_interface

This commit is contained in:
Mohammad Salameh
2024-04-17 14:01:54 +03:00
9 changed files with 143 additions and 154 deletions

View File

@ -20,8 +20,9 @@ class AuthCubit extends Cubit<AuthState> {
static AuthCubit get(context) => BlocProvider.of(context);
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
final TextEditingController emailController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final loginFormKey = GlobalKey<FormState>();
bool isPasswordVisible = false;
static GlobalKey<FormState> formKey = GlobalKey<FormState>();
@ -41,6 +42,56 @@ class AuthCubit extends Cubit<AuthState> {
static UserModel? user;
static Token token = Token.emptyConstructor();
/////////////////////////////////////VALIDATORS/////////////////////////////////////
String? passwordValidator(String? value) {
if (value != null) {
if (value.isNotEmpty) {
if (value.length >= 6) {
return null;
//TODO uncomment this code when the password validation is needed
// if (RegExp(
// r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$')
// .hasMatch(value)) {
// return null;
// } else {
// return 'Password must contain at least one uppercase letter, one lowercase letter, one number and one special character';
// }
} else {
return 'Password must be at least 6 characters';
}
} else {
return 'Please enter your password';
}
}
return null;
}
String? emailAddressValidator(String? value) {
if (value != null && value.isNotEmpty && value != "") {
if (checkValidityOfEmail(value)) {
if (loginFormKey.currentState != null) {
loginFormKey.currentState!.save();
}
return null;
} else {
return 'Please enter a valid email';
}
} else {
return 'Email address is required';
}
}
bool checkValidityOfEmail(String? email) {
if (email != null) {
return RegExp(
r"^[a-zA-Z0-9]+([.!#$%&'*+/=?^_`{|}~-]?[a-zA-Z0-9]+)*@[a-zA-Z0-9]+([.-]?[a-zA-Z0-9]+)*\.[a-zA-Z0-9]{2,}$")
.hasMatch(email);
} else {
return false;
}
}
/////////////////////////////////////API CALLS/////////////////////////////////////
login() async {
emit(AuthLoginLoading());

View File

@ -13,9 +13,10 @@ class LoginForm extends StatelessWidget {
@override
Widget build(BuildContext context) {
var formKey = GlobalKey<FormState>();
var pressed = false;
return BlocBuilder<AuthCubit, AuthState>(
builder: (context, state) {
final formKey = AuthCubit.get(context).loginFormKey;
return Form(
key: formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
@ -28,30 +29,23 @@ class LoginForm extends StatelessWidget {
fontColor: Colors.white,
),
TextFormField(
autovalidateMode: AutovalidateMode.disabled,
textInputAction: TextInputAction.done,
keyboardType: TextInputType.text,
scrollPadding: EdgeInsets.zero,
autocorrect: false,
autofillHints: const [AutofillHints.email],
controller: AuthCubit.get(context).emailController,
validator: (value) {
if (state is! AuthTokenError) {
if (value != null) {
if (value.isNotEmpty) {
if (RegExp(
r'^[a-zA-Z0-9._-]+@{1}[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$')
.hasMatch(value)) {
if (state is AuthTokenError && !pressed) {
return null;
} else {
return 'Please enter a valid email';
}
} else {
return 'Please enter your email';
}
} else {
return 'Please enter your email';
}
}
return null;
return AuthCubit.get(context).emailAddressValidator(value);
},
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
onChanged: (value) {},
decoration: defaultInputDecoration(context,
hint: "Example@email.com"),
),
@ -61,30 +55,18 @@ class LoginForm extends StatelessWidget {
fontColor: Colors.white,
),
TextFormField(
autovalidateMode: AutovalidateMode.disabled,
textInputAction: TextInputAction.done,
keyboardType: TextInputType.text,
scrollPadding: EdgeInsets.zero,
autocorrect: false,
autofillHints: const [AutofillHints.password],
controller: AuthCubit.get(context).passwordController,
validator: (value) {
if (state is! AuthTokenError) {
if (value != null) {
if (value.isNotEmpty) {
if (state is AuthTokenError && !pressed) {
return null;
//TODO: uncomment this when the backend is ready
// if (value.length > 8) {
// if (RegExp(
// r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$')
// .hasMatch(value)) {
// return null;
// } else {
// return 'Password must contain at least one uppercase letter, one lowercase letter, one number and one special character';
// }
// } else {
// return 'Password must be at least 8 characters';
// }
} else {
return 'Please enter your password';
}
}
}
return null;
return AuthCubit.get(context).passwordValidator(value);
},
onTapOutside: (event) {
FocusScope.of(context).unfocus();
@ -116,14 +98,11 @@ class LoginForm extends StatelessWidget {
'Login',
),
onPressed: () {
bool isValid = formKey.currentState!.validate();
if (isValid) {
pressed = true;
if (formKey.currentState!.validate()) {
if ((state is! AuthLoading)) {
print('login');
AuthCubit.get(context).login();
FocusScope.of(context).unfocus();
} else {
formKey.currentState!.save();
}
}
},

View File

@ -16,16 +16,11 @@ class AuthenticationAPI {
static Future<Token> loginWithEmail(
{required LoginWithEmailModel model}) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.login,
body: model.toJson(),
showServerMessage: false,
expectedResponseModel: (json) => Token.fromJson(json['data']));
// developer.log("response: $response");
return response;
} catch (e) {
rethrow;
}
}
}

View File

@ -30,7 +30,7 @@ class DevicesAPI {
"pageSize": 100,
"pageNo": 1
};
try {
final response = await _httpService.get(
path: ApiEndpoints.groups,
queryParameters: params,
@ -39,13 +39,9 @@ class DevicesAPI {
DevicesCategoryModel.fromJsonList(json['groups']),
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> getDeviceStatus(String deviceId) async {
try {
final response = await _httpService.get(
path: '${ApiEndpoints.deviceStatus}/$deviceId/functions/status',
showServerMessage: false,
@ -54,13 +50,9 @@ class DevicesAPI {
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<List<DeviceModel>> getDevicesByRoomId(int roomId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.devicesByRoom,
queryParameters: {"roomId": roomId, "pageSize": 10},
@ -74,8 +66,5 @@ class DevicesAPI {
},
);
return response;
} catch (e) {
rethrow;
}
}
}

View File

@ -42,11 +42,6 @@ class HTTPInterceptor extends InterceptorsWrapper {
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
// developer.log('Error Message: ${err.message}');
// developer.log('Error res Code: ${err.response?.statusCode}');
// developer.log('Error res Data: ${err.response?.data}');
// developer.log('Error res status message: ${err.response?.statusMessage}');
ServerFailure failure = ServerFailure.fromDioError(err);
CustomSnackBar.displaySnackBar(failure.toString());
var storage = const FlutterSecureStorage();

View File

@ -74,11 +74,8 @@ class HTTPService {
data: body,
queryParameters: queryParameters,
);
developer.log("status code is ${response.statusCode}");
return expectedResponseModel(response.data);
} catch (error) {
developer.log("******* Error");
developer.log(error.toString());
rethrow;
}
}
@ -89,21 +86,15 @@ class HTTPService {
Map<String, dynamic>? queryParameters,
required T Function(dynamic) expectedResponseModel}) async {
try {
developer.log("download begins");
final response = await client.download(
path,
savePath,
onReceiveProgress: (current, total) {
developer.log("current = $current, while total = $total");
},
onReceiveProgress: (current, total) {},
);
developer.log("download ends");
return expectedResponseModel(response.data);
// return expectedResponseModel(response.data);
} catch (error) {
developer.log("******* Error");
developer.log("download error");
developer.log(error.toString());
rethrow;
}
}
@ -121,8 +112,6 @@ class HTTPService {
);
return expectedResponseModel(response.data);
} catch (error) {
developer.log("******* Error");
developer.log(error.toString());
rethrow;
}
}

View File

@ -32,7 +32,7 @@ class ServerFailure extends Failure {
// var document = parser.parse(dioError.response!.data.toString());
// var message = document.body!.text;
return ServerFailure.fromResponse(dioError.response!.statusCode!,
dioError.response!.data['message']);
dioError.response?.data['message'] ?? "Error");
}
case DioExceptionType.cancel:
return ServerFailure("The request to ApiServer was canceled");
@ -48,25 +48,25 @@ class ServerFailure extends Failure {
}
}
factory ServerFailure.fromResponse(int? statusCode, dynamic response) {
factory ServerFailure.fromResponse(int? statusCode, dynamic responseMessage) {
switch (statusCode) {
case 401:
case 403:
return ServerFailure(response);
return ServerFailure(responseMessage);
case 400:
List<String> errors = [];
if (response['message'] is List) {
for (var error in response['message']) {
if (responseMessage is List) {
for (var error in responseMessage) {
errors.add(error);
}
} else {
errors.add(response['message']);
return ServerFailure(responseMessage);
}
return ServerFailure(errors.join('\n'));
case 404:
return ServerFailure("Your request not found, Please try later!");
case 500:
return ServerFailure(response);
return ServerFailure(responseMessage);
default:
return ServerFailure("Opps there was an Error, Please try again!");
}

View File

@ -12,7 +12,6 @@ class SpacesAPI {
static Future<List<SpaceModel>> getSpaces() async {
var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
try {
final response = await _httpService.get(
path: ApiEndpoints.spaces,
queryParameters: {
@ -22,14 +21,10 @@ class SpacesAPI {
expectedResponseModel: (json) => SpaceModel.fromJsonList(json),
);
return response;
} catch (e) {
rethrow;
}
}
//get rooms by space id
static Future<List<RoomModel>> getRoomsBySpaceId(int spaceId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.rooms,
queryParameters: {"homeId": spaceId},
@ -43,8 +38,5 @@ class SpacesAPI {
},
);
return response;
} catch (e) {
rethrow;
}
}
}

View File

@ -6,7 +6,6 @@ class StringHelpers {
static String enhanceFileName(File file) {
var fileName = " ";
final filePath = file.path;
developer.log(filePath);
final fileStringArray = filePath.split("/");
fileName = fileStringArray.last;
if (fileName.length > 20) {