mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-08-25 18:39:39 +00:00
211 lines
6.5 KiB
Dart
211 lines
6.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:dio/dio.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_event.dart';
|
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_state.dart';
|
|
import 'package:syncrow_app/services/api/authentication_api.dart';
|
|
|
|
class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
|
|
bool _isPasswordVisible = false;
|
|
String otpCode = '';
|
|
String validate = '';
|
|
SecurityBloc() : super(PasswordVisibilityState(false)) {
|
|
on<SetPassword>(_onSetPassword);
|
|
on<TogglePasswordVisibility>(_onTogglePasswordVisibility);
|
|
on<StartTimerEvent>(_onStartTimer);
|
|
on<StopTimerEvent>(_onStopTimer);
|
|
on<UpdateTimerEvent>(_onUpdateTimer);
|
|
on<VerifyPassCodeEvent>(verifyCode);
|
|
on<ChangePasswordEvent>(changePassword);
|
|
on<DeleteAccountEvent>(onDeleteAccountEvent);
|
|
}
|
|
|
|
void _onSetPassword(SetPassword event, Emitter<SecurityState> emit) {
|
|
if (event.password.length < 6) {
|
|
emit(PasswordErrorState('Password must be at least 6 characters long.'));
|
|
} else {
|
|
emit(PasswordSetState('Password successfully set.'));
|
|
}
|
|
}
|
|
|
|
void _onTogglePasswordVisibility(
|
|
TogglePasswordVisibility event, Emitter<SecurityState> emit) {
|
|
_isPasswordVisible = !_isPasswordVisible;
|
|
emit(PasswordVisibilityState(_isPasswordVisible));
|
|
}
|
|
|
|
String? passwordValidator(String? value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Please enter your password';
|
|
}
|
|
List<String> validationErrors = [];
|
|
|
|
if (!RegExp(r'^(?=.*[a-z])').hasMatch(value)) {
|
|
validationErrors.add(' - one lowercase letter');
|
|
}
|
|
if (!RegExp(r'^(?=.*[A-Z])').hasMatch(value)) {
|
|
validationErrors.add(' - one uppercase letter');
|
|
}
|
|
if (!RegExp(r'^(?=.*\d)').hasMatch(value)) {
|
|
validationErrors.add(' - one number');
|
|
}
|
|
if (!RegExp(r'^(?=.*[@$!%*?&])').hasMatch(value)) {
|
|
validationErrors.add(' - one special character');
|
|
}
|
|
if (value.length < 8) {
|
|
validationErrors.add(' - minimum 8 characters');
|
|
}
|
|
|
|
if (validationErrors.isNotEmpty) {
|
|
return 'Password must contain at least:\n${validationErrors.join('\n')}';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
TextEditingController newPassword = TextEditingController();
|
|
|
|
Timer? _timer;
|
|
int _remainingTime = 0;
|
|
|
|
Future _onStartTimer(
|
|
StartTimerEvent event, Emitter<SecurityState> emit) async {
|
|
if (_timer != null && _timer!.isActive) {
|
|
return;
|
|
}
|
|
_remainingTime = 1;
|
|
add(UpdateTimerEvent(
|
|
remainingTime: _remainingTime, isButtonEnabled: false));
|
|
try {
|
|
_remainingTime = 30;
|
|
var res = (await AuthenticationAPI.sendOtp(body: {
|
|
'email': HomeCubit.user!.email,
|
|
'type': 'PASSWORD',
|
|
if (HomeCubit.user!.regionUuid != null)
|
|
'regionUuid': HomeCubit.user!.regionUuid
|
|
}));
|
|
_remainingTime = res['cooldown'];
|
|
} on DioException catch (e) {
|
|
if (e.response!.statusCode == 400) {
|
|
final errorData = e.response!.data;
|
|
String errorMessage = errorData['message'];
|
|
if (errorMessage == 'User not found') {
|
|
validate = 'Invalid Credential';
|
|
emit(AuthInitialState());
|
|
return 1;
|
|
} else {
|
|
validate = '';
|
|
_remainingTime = errorData['data']['cooldown'] ?? 1;
|
|
emit(AuthInitialState());
|
|
}
|
|
} else {
|
|
emit(AuthInitialState());
|
|
|
|
return 1;
|
|
}
|
|
emit(AuthInitialState());
|
|
} catch (e) {
|
|
emit(AuthInitialState());
|
|
|
|
return 1;
|
|
}
|
|
|
|
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
|
_remainingTime--;
|
|
if (_remainingTime <= 0) {
|
|
_timer?.cancel();
|
|
add(UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
|
} else {
|
|
add(UpdateTimerEvent(
|
|
remainingTime: _remainingTime, isButtonEnabled: false));
|
|
}
|
|
});
|
|
}
|
|
|
|
void _onStopTimer(StopTimerEvent event, Emitter<SecurityState> emit) {
|
|
_timer?.cancel();
|
|
emit(TimerState(isButtonEnabled: true, remainingTime: 0));
|
|
}
|
|
|
|
void _onUpdateTimer(UpdateTimerEvent event, Emitter<SecurityState> emit) {
|
|
emit(TimerState(
|
|
isButtonEnabled: event.isButtonEnabled,
|
|
remainingTime: event.remainingTime));
|
|
}
|
|
|
|
String formattedTime(int time) {
|
|
final int days = (time / 86400).floor(); // 86400 seconds in a day
|
|
final int hours = ((time % 86400) / 3600).floor();
|
|
final int minutes = (((time % 86400) % 3600) / 60).floor();
|
|
final int seconds = (((time % 86400) % 3600) % 60).floor();
|
|
|
|
final String formattedTime = [
|
|
if (days > 0) '${days}d', // Append 'd' for days
|
|
if (days > 0 || hours > 0)
|
|
hours
|
|
.toString()
|
|
.padLeft(2, '0'), // Show hours if there are days or hours
|
|
minutes.toString().padLeft(2, '0'),
|
|
seconds.toString().padLeft(2, '0'),
|
|
].join(':');
|
|
|
|
return formattedTime;
|
|
}
|
|
|
|
Future<void> verifyCode(
|
|
VerifyPassCodeEvent event, Emitter<SecurityState> emit) async {
|
|
emit(LoadingForgetState());
|
|
try {
|
|
final response = await AuthenticationAPI.verifyPassCode(body: {
|
|
'email': HomeCubit.user!.email!,
|
|
'type': 'PASSWORD',
|
|
'otpCode': otpCode
|
|
});
|
|
if (response['statusCode'] == 200) {
|
|
_timer?.cancel();
|
|
emit(SuccessForgetState());
|
|
}
|
|
} on DioException catch (e) {
|
|
final errorData = e.response!.data;
|
|
String errorMessage =
|
|
errorData['error']['message'] ?? 'something went wrong';
|
|
validate = errorMessage;
|
|
emit(AuthInitialState());
|
|
}
|
|
}
|
|
|
|
Future<void> changePassword(
|
|
ChangePasswordEvent event, Emitter<SecurityState> emit) async {
|
|
emit(LoadingForgetState());
|
|
try {
|
|
final response = await AuthenticationAPI.forgetPassword(
|
|
email: HomeCubit.user!.email!,
|
|
otpCode: event.otpCode,
|
|
password: newPassword.text,
|
|
);
|
|
emit(ChangedPassState());
|
|
} on DioException catch (e) {
|
|
final errorData = e.response!.data;
|
|
String errorMessage =
|
|
errorData['error']['message'] ?? 'something went wrong';
|
|
validate = errorMessage;
|
|
emit(AuthInitialState());
|
|
}
|
|
}
|
|
|
|
Future<void> onDeleteAccountEvent(
|
|
DeleteAccountEvent event, Emitter<SecurityState> emit) async {
|
|
emit(LoadingForgetState());
|
|
try {
|
|
await AuthenticationAPI.deleteAccount();
|
|
emit(ChangedPassState());
|
|
} catch (e) {
|
|
validate = e.toString();
|
|
emit(AuthInitialState());
|
|
}
|
|
}
|
|
}
|