Merge branch 'refs/heads/feature/chicken' into feature/inspectionV1.0.2
# Conflicts: # packages/auth/lib/presentation/pages/auth/view.dart # packages/auth/pubspec.yaml # packages/core/lib/presentation/widget/app_bar/r_app_bar.dart # packages/core/lib/presentation/widget/inputs/r_input.dart
This commit is contained in:
@@ -5,10 +5,14 @@ class DioErrorHandler {
|
||||
void handle(DioException error) {
|
||||
switch (error.response?.statusCode) {
|
||||
case 401:
|
||||
_handle401();
|
||||
_handleGeneric(error);
|
||||
break;
|
||||
case 403:
|
||||
_handle403();
|
||||
_handleGeneric(error);
|
||||
break;
|
||||
|
||||
case 410:
|
||||
_handle410();
|
||||
break;
|
||||
default:
|
||||
_handleGeneric(error);
|
||||
@@ -16,21 +20,22 @@ class DioErrorHandler {
|
||||
}
|
||||
|
||||
//wrong password/user name => "detail": "No active account found with the given credentials" - 401
|
||||
void _handle401() {
|
||||
Get.showSnackbar(
|
||||
_errorSnackBar('نام کاربری یا رمز عبور اشتباه است'),
|
||||
);
|
||||
void _handle410() {
|
||||
Get.showSnackbar(_errorSnackBar('نام کاربری یا رمز عبور اشتباه است'));
|
||||
}
|
||||
|
||||
//wrong captcha => "detail": "Captcha code is incorrect" - 403
|
||||
void _handle403() {
|
||||
Get.showSnackbar(
|
||||
_errorSnackBar('کد امنیتی اشتباه است'),
|
||||
);
|
||||
}
|
||||
void _handle403() {}
|
||||
|
||||
void _handleGeneric(DioException error) {
|
||||
// General error handling
|
||||
Get.showSnackbar(
|
||||
_errorSnackBar(
|
||||
error.response?.data.keys.first == 'is_user'
|
||||
? 'کاربر با این شماره تلفن وجود ندارد'
|
||||
: error.response?.data[error.response?.data.keys.first] ??
|
||||
'خطا در برقراری ارتباط با سرور',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
GetSnackBar _errorSnackBar(String message) {
|
||||
|
||||
@@ -4,15 +4,21 @@ import 'package:rasadyar_core/core.dart';
|
||||
import '../di/auth_di.dart';
|
||||
import 'constant.dart';
|
||||
|
||||
/*
|
||||
class DioRemoteManager {
|
||||
DioRemote? _currentClient;
|
||||
ApiEnvironment? _currentEnv;
|
||||
|
||||
Future<DioRemote> setEnvironment([
|
||||
ApiEnvironment env = ApiEnvironment.dam,
|
||||
]) async {
|
||||
Future<DioRemote> setEnvironment([ApiEnvironment env = ApiEnvironment.dam]) async {
|
||||
if (_currentEnv != env) {
|
||||
_currentClient = DioRemote(env.baseUrl);
|
||||
_currentClient = DioRemote(
|
||||
baseUrl: env.baseUrl,
|
||||
interceptors: AppInterceptor(
|
||||
refreshTokenCallback: () async{
|
||||
return null;
|
||||
},
|
||||
),
|
||||
);
|
||||
await _currentClient?.init();
|
||||
_currentEnv = env;
|
||||
}
|
||||
@@ -39,7 +45,6 @@ Future<void> switchAuthEnvironment(ApiEnvironment env) async {
|
||||
await diAuth.unregister<AuthRepositoryImpl>();
|
||||
}
|
||||
|
||||
diAuth.registerLazySingleton<AuthRepositoryImpl>(
|
||||
() => AuthRepositoryImpl(dioRemote),
|
||||
);
|
||||
diAuth.registerLazySingleton<AuthRepositoryImpl>(() => AuthRepositoryImpl(dioRemote));
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:rasadyar_auth/data/common/constant.dart';
|
||||
import 'package:rasadyar_auth/data/common/dio_error_handler.dart';
|
||||
import 'package:rasadyar_auth/data/models/response/auth/auth_response_model.dart';
|
||||
import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart';
|
||||
import 'package:rasadyar_auth/data/services/token_storage_service.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
@@ -9,13 +9,54 @@ import '../common/dio_manager.dart';
|
||||
GetIt diAuth = GetIt.instance;
|
||||
|
||||
Future<void> setupAuthDI() async {
|
||||
diAuth.registerLazySingleton(() => DioRemoteManager());
|
||||
|
||||
diAuth.registerLazySingleton<AppInterceptor>(
|
||||
() => AppInterceptor(
|
||||
refreshTokenCallback: () async {
|
||||
var tokenService = Get.find<TokenStorageService>();
|
||||
final authRepo = diAuth.get<AuthRepositoryImpl>();
|
||||
|
||||
final manager = diAuth.get<DioRemoteManager>();
|
||||
final dioRemote = await manager.setEnvironment(ApiEnvironment.dam);
|
||||
diAuth.registerCachedFactory<AuthRepositoryImpl>(
|
||||
() => AuthRepositoryImpl(dioRemote),
|
||||
final refreshToken = tokenService.refreshToken.value;
|
||||
if (refreshToken == null) return null;
|
||||
|
||||
final result = await authRepo.loginWithRefreshToken(
|
||||
authRequest: {"refresh_token": refreshToken},
|
||||
);
|
||||
|
||||
if (result is AuthResponseModel) {
|
||||
await tokenService.saveAccessToken(result.access!);
|
||||
return result.access;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
saveTokenCallback: (String newToken) async {
|
||||
//
|
||||
},
|
||||
clearTokenCallback: () async {
|
||||
//await tokenService.clearTokens(); // حذف همه توکنها
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
diAuth.registerLazySingleton<DioRemote>(
|
||||
() => DioRemote(interceptors: diAuth.get<AppInterceptor>()),
|
||||
);
|
||||
|
||||
final dioRemote = diAuth.get<DioRemote>();
|
||||
await dioRemote.init();
|
||||
diAuth.registerSingleton<AuthRepositoryImpl>(AuthRepositoryImpl(dioRemote));
|
||||
diAuth.registerLazySingleton<DioErrorHandler>(() => DioErrorHandler());
|
||||
}
|
||||
|
||||
Future<void> newSetupAuthDI(String newUrl) async {
|
||||
diAuth.registerLazySingleton<DioRemote>(
|
||||
() => DioRemote(baseUrl: newUrl, interceptors: diAuth.get<AppInterceptor>()),
|
||||
instanceName: 'newRemote',
|
||||
);
|
||||
final dioRemote = diAuth.get<DioRemote>(instanceName: 'newRemote');
|
||||
await dioRemote.init();
|
||||
diAuth.registerSingleton<AuthRepositoryImpl>(
|
||||
AuthRepositoryImpl(dioRemote),
|
||||
instanceName: 'newUrl',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:rasadyar_auth/auth.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
import 'package:rasadyar_core/utils/local/local_utils.dart';
|
||||
|
||||
part 'user_local_model.g.dart';
|
||||
|
||||
@HiveType(typeId: 0)
|
||||
@HiveType(typeId: authUserLocalModelTypeId)
|
||||
class UserLocalModel extends HiveObject {
|
||||
@HiveField(0)
|
||||
String? username;
|
||||
@@ -19,6 +19,12 @@ class UserLocalModel extends HiveObject {
|
||||
@HiveField(5)
|
||||
Module? module;
|
||||
|
||||
@HiveField(6)
|
||||
String? backend;
|
||||
|
||||
@HiveField(7)
|
||||
String? apiKey;
|
||||
|
||||
UserLocalModel({
|
||||
this.username,
|
||||
this.password,
|
||||
@@ -26,6 +32,8 @@ class UserLocalModel extends HiveObject {
|
||||
this.refreshToken,
|
||||
this.name,
|
||||
this.module,
|
||||
this.backend,
|
||||
this.apiKey,
|
||||
});
|
||||
|
||||
UserLocalModel copyWith({
|
||||
@@ -35,6 +43,8 @@ class UserLocalModel extends HiveObject {
|
||||
String? refreshToken,
|
||||
String? name,
|
||||
Module? module,
|
||||
String? backend,
|
||||
String? apiKey,
|
||||
}) {
|
||||
return UserLocalModel(
|
||||
username: username ?? this.username,
|
||||
@@ -43,14 +53,18 @@ class UserLocalModel extends HiveObject {
|
||||
refreshToken: refreshToken ?? this.refreshToken,
|
||||
name: name ?? this.name,
|
||||
module: module ?? this.module,
|
||||
backend: backend ?? this.backend,
|
||||
apiKey: apiKey ?? this.apiKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@HiveType(typeId: 1)
|
||||
@HiveType(typeId: authModuleTypeId)
|
||||
enum Module {
|
||||
@HiveField(0)
|
||||
liveStocks,
|
||||
@HiveField(1)
|
||||
inspection,
|
||||
@HiveField(2)
|
||||
chicken,
|
||||
}
|
||||
|
||||
@@ -23,13 +23,15 @@ class UserLocalModelAdapter extends TypeAdapter<UserLocalModel> {
|
||||
refreshToken: fields[3] as String?,
|
||||
name: fields[4] as String?,
|
||||
module: fields[5] as Module?,
|
||||
backend: fields[6] as String?,
|
||||
apiKey: fields[7] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, UserLocalModel obj) {
|
||||
writer
|
||||
..writeByte(6)
|
||||
..writeByte(8)
|
||||
..writeByte(0)
|
||||
..write(obj.username)
|
||||
..writeByte(1)
|
||||
@@ -41,7 +43,11 @@ class UserLocalModelAdapter extends TypeAdapter<UserLocalModel> {
|
||||
..writeByte(4)
|
||||
..write(obj.name)
|
||||
..writeByte(5)
|
||||
..write(obj.module);
|
||||
..write(obj.module)
|
||||
..writeByte(6)
|
||||
..write(obj.backend)
|
||||
..writeByte(7)
|
||||
..write(obj.apiKey);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -66,6 +72,8 @@ class ModuleAdapter extends TypeAdapter<Module> {
|
||||
return Module.liveStocks;
|
||||
case 1:
|
||||
return Module.inspection;
|
||||
case 2:
|
||||
return Module.chicken;
|
||||
default:
|
||||
return Module.liveStocks;
|
||||
}
|
||||
@@ -78,6 +86,8 @@ class ModuleAdapter extends TypeAdapter<Module> {
|
||||
writer.writeByte(0);
|
||||
case Module.inspection:
|
||||
writer.writeByte(1);
|
||||
case Module.chicken:
|
||||
writer.writeByte(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
part 'user_info_model.freezed.dart';
|
||||
|
||||
part 'user_info_model.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class UserInfoModel with _$UserInfoModel {
|
||||
const factory UserInfoModel({
|
||||
bool? isUser,
|
||||
String? address,
|
||||
String? backend,
|
||||
String? apiKey,
|
||||
}) = _UserInfoModel ;
|
||||
|
||||
factory UserInfoModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$UserInfoModelFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
// dart format width=80
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'user_info_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$UserInfoModel {
|
||||
|
||||
bool? get isUser; String? get address; String? get backend; String? get apiKey;
|
||||
/// Create a copy of UserInfoModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$UserInfoModelCopyWith<UserInfoModel> get copyWith => _$UserInfoModelCopyWithImpl<UserInfoModel>(this as UserInfoModel, _$identity);
|
||||
|
||||
/// Serializes this UserInfoModel to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is UserInfoModel&&(identical(other.isUser, isUser) || other.isUser == isUser)&&(identical(other.address, address) || other.address == address)&&(identical(other.backend, backend) || other.backend == backend)&&(identical(other.apiKey, apiKey) || other.apiKey == apiKey));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isUser,address,backend,apiKey);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserInfoModel(isUser: $isUser, address: $address, backend: $backend, apiKey: $apiKey)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $UserInfoModelCopyWith<$Res> {
|
||||
factory $UserInfoModelCopyWith(UserInfoModel value, $Res Function(UserInfoModel) _then) = _$UserInfoModelCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool? isUser, String? address, String? backend, String? apiKey
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$UserInfoModelCopyWithImpl<$Res>
|
||||
implements $UserInfoModelCopyWith<$Res> {
|
||||
_$UserInfoModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final UserInfoModel _self;
|
||||
final $Res Function(UserInfoModel) _then;
|
||||
|
||||
/// Create a copy of UserInfoModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isUser = freezed,Object? address = freezed,Object? backend = freezed,Object? apiKey = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
isUser: freezed == isUser ? _self.isUser : isUser // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,address: freezed == address ? _self.address : address // ignore: cast_nullable_to_non_nullable
|
||||
as String?,backend: freezed == backend ? _self.backend : backend // ignore: cast_nullable_to_non_nullable
|
||||
as String?,apiKey: freezed == apiKey ? _self.apiKey : apiKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _UserInfoModel implements UserInfoModel {
|
||||
const _UserInfoModel({this.isUser, this.address, this.backend, this.apiKey});
|
||||
factory _UserInfoModel.fromJson(Map<String, dynamic> json) => _$UserInfoModelFromJson(json);
|
||||
|
||||
@override final bool? isUser;
|
||||
@override final String? address;
|
||||
@override final String? backend;
|
||||
@override final String? apiKey;
|
||||
|
||||
/// Create a copy of UserInfoModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$UserInfoModelCopyWith<_UserInfoModel> get copyWith => __$UserInfoModelCopyWithImpl<_UserInfoModel>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$UserInfoModelToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _UserInfoModel&&(identical(other.isUser, isUser) || other.isUser == isUser)&&(identical(other.address, address) || other.address == address)&&(identical(other.backend, backend) || other.backend == backend)&&(identical(other.apiKey, apiKey) || other.apiKey == apiKey));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isUser,address,backend,apiKey);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserInfoModel(isUser: $isUser, address: $address, backend: $backend, apiKey: $apiKey)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$UserInfoModelCopyWith<$Res> implements $UserInfoModelCopyWith<$Res> {
|
||||
factory _$UserInfoModelCopyWith(_UserInfoModel value, $Res Function(_UserInfoModel) _then) = __$UserInfoModelCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool? isUser, String? address, String? backend, String? apiKey
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$UserInfoModelCopyWithImpl<$Res>
|
||||
implements _$UserInfoModelCopyWith<$Res> {
|
||||
__$UserInfoModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _UserInfoModel _self;
|
||||
final $Res Function(_UserInfoModel) _then;
|
||||
|
||||
/// Create a copy of UserInfoModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isUser = freezed,Object? address = freezed,Object? backend = freezed,Object? apiKey = freezed,}) {
|
||||
return _then(_UserInfoModel(
|
||||
isUser: freezed == isUser ? _self.isUser : isUser // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,address: freezed == address ? _self.address : address // ignore: cast_nullable_to_non_nullable
|
||||
as String?,backend: freezed == backend ? _self.backend : backend // ignore: cast_nullable_to_non_nullable
|
||||
as String?,apiKey: freezed == apiKey ? _self.apiKey : apiKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -0,0 +1,23 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'user_info_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_UserInfoModel _$UserInfoModelFromJson(Map<String, dynamic> json) =>
|
||||
_UserInfoModel(
|
||||
isUser: json['is_user'] as bool?,
|
||||
address: json['address'] as String?,
|
||||
backend: json['backend'] as String?,
|
||||
apiKey: json['api_key'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$UserInfoModelToJson(_UserInfoModel instance) =>
|
||||
<String, dynamic>{
|
||||
'is_user': instance.isUser,
|
||||
'address': instance.address,
|
||||
'backend': instance.backend,
|
||||
'api_key': instance.apiKey,
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'user_profile_model.freezed.dart';
|
||||
|
||||
part 'user_profile_model.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class UserProfileModel with _$UserProfileModel {
|
||||
const factory UserProfileModel({
|
||||
String? accessToken,
|
||||
String? expiresIn,
|
||||
String? scope,
|
||||
String? expireTime,
|
||||
String? mobile,
|
||||
String? fullname,
|
||||
String? firstname,
|
||||
String? lastname,
|
||||
String? city,
|
||||
String? province,
|
||||
String? nationalCode,
|
||||
String? nationalId,
|
||||
String? birthday,
|
||||
String? image,
|
||||
int? baseOrder,
|
||||
List<String>? role,
|
||||
}) = _UserProfileModel;
|
||||
|
||||
factory UserProfileModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$UserProfileModelFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
// dart format width=80
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'user_profile_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$UserProfileModel {
|
||||
|
||||
String? get accessToken; String? get expiresIn; String? get scope; String? get expireTime; String? get mobile; String? get fullname; String? get firstname; String? get lastname; String? get city; String? get province; String? get nationalCode; String? get nationalId; String? get birthday; String? get image; int? get baseOrder; List<String>? get role;
|
||||
/// Create a copy of UserProfileModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$UserProfileModelCopyWith<UserProfileModel> get copyWith => _$UserProfileModelCopyWithImpl<UserProfileModel>(this as UserProfileModel, _$identity);
|
||||
|
||||
/// Serializes this UserProfileModel to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is UserProfileModel&&(identical(other.accessToken, accessToken) || other.accessToken == accessToken)&&(identical(other.expiresIn, expiresIn) || other.expiresIn == expiresIn)&&(identical(other.scope, scope) || other.scope == scope)&&(identical(other.expireTime, expireTime) || other.expireTime == expireTime)&&(identical(other.mobile, mobile) || other.mobile == mobile)&&(identical(other.fullname, fullname) || other.fullname == fullname)&&(identical(other.firstname, firstname) || other.firstname == firstname)&&(identical(other.lastname, lastname) || other.lastname == lastname)&&(identical(other.city, city) || other.city == city)&&(identical(other.province, province) || other.province == province)&&(identical(other.nationalCode, nationalCode) || other.nationalCode == nationalCode)&&(identical(other.nationalId, nationalId) || other.nationalId == nationalId)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&(identical(other.image, image) || other.image == image)&&(identical(other.baseOrder, baseOrder) || other.baseOrder == baseOrder)&&const DeepCollectionEquality().equals(other.role, role));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,accessToken,expiresIn,scope,expireTime,mobile,fullname,firstname,lastname,city,province,nationalCode,nationalId,birthday,image,baseOrder,const DeepCollectionEquality().hash(role));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserProfileModel(accessToken: $accessToken, expiresIn: $expiresIn, scope: $scope, expireTime: $expireTime, mobile: $mobile, fullname: $fullname, firstname: $firstname, lastname: $lastname, city: $city, province: $province, nationalCode: $nationalCode, nationalId: $nationalId, birthday: $birthday, image: $image, baseOrder: $baseOrder, role: $role)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $UserProfileModelCopyWith<$Res> {
|
||||
factory $UserProfileModelCopyWith(UserProfileModel value, $Res Function(UserProfileModel) _then) = _$UserProfileModelCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String? accessToken, String? expiresIn, String? scope, String? expireTime, String? mobile, String? fullname, String? firstname, String? lastname, String? city, String? province, String? nationalCode, String? nationalId, String? birthday, String? image, int? baseOrder, List<String>? role
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$UserProfileModelCopyWithImpl<$Res>
|
||||
implements $UserProfileModelCopyWith<$Res> {
|
||||
_$UserProfileModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final UserProfileModel _self;
|
||||
final $Res Function(UserProfileModel) _then;
|
||||
|
||||
/// Create a copy of UserProfileModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? accessToken = freezed,Object? expiresIn = freezed,Object? scope = freezed,Object? expireTime = freezed,Object? mobile = freezed,Object? fullname = freezed,Object? firstname = freezed,Object? lastname = freezed,Object? city = freezed,Object? province = freezed,Object? nationalCode = freezed,Object? nationalId = freezed,Object? birthday = freezed,Object? image = freezed,Object? baseOrder = freezed,Object? role = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
accessToken: freezed == accessToken ? _self.accessToken : accessToken // ignore: cast_nullable_to_non_nullable
|
||||
as String?,expiresIn: freezed == expiresIn ? _self.expiresIn : expiresIn // ignore: cast_nullable_to_non_nullable
|
||||
as String?,scope: freezed == scope ? _self.scope : scope // ignore: cast_nullable_to_non_nullable
|
||||
as String?,expireTime: freezed == expireTime ? _self.expireTime : expireTime // ignore: cast_nullable_to_non_nullable
|
||||
as String?,mobile: freezed == mobile ? _self.mobile : mobile // ignore: cast_nullable_to_non_nullable
|
||||
as String?,fullname: freezed == fullname ? _self.fullname : fullname // ignore: cast_nullable_to_non_nullable
|
||||
as String?,firstname: freezed == firstname ? _self.firstname : firstname // ignore: cast_nullable_to_non_nullable
|
||||
as String?,lastname: freezed == lastname ? _self.lastname : lastname // ignore: cast_nullable_to_non_nullable
|
||||
as String?,city: freezed == city ? _self.city : city // ignore: cast_nullable_to_non_nullable
|
||||
as String?,province: freezed == province ? _self.province : province // ignore: cast_nullable_to_non_nullable
|
||||
as String?,nationalCode: freezed == nationalCode ? _self.nationalCode : nationalCode // ignore: cast_nullable_to_non_nullable
|
||||
as String?,nationalId: freezed == nationalId ? _self.nationalId : nationalId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,birthday: freezed == birthday ? _self.birthday : birthday // ignore: cast_nullable_to_non_nullable
|
||||
as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable
|
||||
as String?,baseOrder: freezed == baseOrder ? _self.baseOrder : baseOrder // ignore: cast_nullable_to_non_nullable
|
||||
as int?,role: freezed == role ? _self.role : role // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _UserProfileModel implements UserProfileModel {
|
||||
const _UserProfileModel({this.accessToken, this.expiresIn, this.scope, this.expireTime, this.mobile, this.fullname, this.firstname, this.lastname, this.city, this.province, this.nationalCode, this.nationalId, this.birthday, this.image, this.baseOrder, final List<String>? role}): _role = role;
|
||||
factory _UserProfileModel.fromJson(Map<String, dynamic> json) => _$UserProfileModelFromJson(json);
|
||||
|
||||
@override final String? accessToken;
|
||||
@override final String? expiresIn;
|
||||
@override final String? scope;
|
||||
@override final String? expireTime;
|
||||
@override final String? mobile;
|
||||
@override final String? fullname;
|
||||
@override final String? firstname;
|
||||
@override final String? lastname;
|
||||
@override final String? city;
|
||||
@override final String? province;
|
||||
@override final String? nationalCode;
|
||||
@override final String? nationalId;
|
||||
@override final String? birthday;
|
||||
@override final String? image;
|
||||
@override final int? baseOrder;
|
||||
final List<String>? _role;
|
||||
@override List<String>? get role {
|
||||
final value = _role;
|
||||
if (value == null) return null;
|
||||
if (_role is EqualUnmodifiableListView) return _role;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of UserProfileModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$UserProfileModelCopyWith<_UserProfileModel> get copyWith => __$UserProfileModelCopyWithImpl<_UserProfileModel>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$UserProfileModelToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _UserProfileModel&&(identical(other.accessToken, accessToken) || other.accessToken == accessToken)&&(identical(other.expiresIn, expiresIn) || other.expiresIn == expiresIn)&&(identical(other.scope, scope) || other.scope == scope)&&(identical(other.expireTime, expireTime) || other.expireTime == expireTime)&&(identical(other.mobile, mobile) || other.mobile == mobile)&&(identical(other.fullname, fullname) || other.fullname == fullname)&&(identical(other.firstname, firstname) || other.firstname == firstname)&&(identical(other.lastname, lastname) || other.lastname == lastname)&&(identical(other.city, city) || other.city == city)&&(identical(other.province, province) || other.province == province)&&(identical(other.nationalCode, nationalCode) || other.nationalCode == nationalCode)&&(identical(other.nationalId, nationalId) || other.nationalId == nationalId)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&(identical(other.image, image) || other.image == image)&&(identical(other.baseOrder, baseOrder) || other.baseOrder == baseOrder)&&const DeepCollectionEquality().equals(other._role, _role));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,accessToken,expiresIn,scope,expireTime,mobile,fullname,firstname,lastname,city,province,nationalCode,nationalId,birthday,image,baseOrder,const DeepCollectionEquality().hash(_role));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserProfileModel(accessToken: $accessToken, expiresIn: $expiresIn, scope: $scope, expireTime: $expireTime, mobile: $mobile, fullname: $fullname, firstname: $firstname, lastname: $lastname, city: $city, province: $province, nationalCode: $nationalCode, nationalId: $nationalId, birthday: $birthday, image: $image, baseOrder: $baseOrder, role: $role)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$UserProfileModelCopyWith<$Res> implements $UserProfileModelCopyWith<$Res> {
|
||||
factory _$UserProfileModelCopyWith(_UserProfileModel value, $Res Function(_UserProfileModel) _then) = __$UserProfileModelCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String? accessToken, String? expiresIn, String? scope, String? expireTime, String? mobile, String? fullname, String? firstname, String? lastname, String? city, String? province, String? nationalCode, String? nationalId, String? birthday, String? image, int? baseOrder, List<String>? role
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$UserProfileModelCopyWithImpl<$Res>
|
||||
implements _$UserProfileModelCopyWith<$Res> {
|
||||
__$UserProfileModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _UserProfileModel _self;
|
||||
final $Res Function(_UserProfileModel) _then;
|
||||
|
||||
/// Create a copy of UserProfileModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? accessToken = freezed,Object? expiresIn = freezed,Object? scope = freezed,Object? expireTime = freezed,Object? mobile = freezed,Object? fullname = freezed,Object? firstname = freezed,Object? lastname = freezed,Object? city = freezed,Object? province = freezed,Object? nationalCode = freezed,Object? nationalId = freezed,Object? birthday = freezed,Object? image = freezed,Object? baseOrder = freezed,Object? role = freezed,}) {
|
||||
return _then(_UserProfileModel(
|
||||
accessToken: freezed == accessToken ? _self.accessToken : accessToken // ignore: cast_nullable_to_non_nullable
|
||||
as String?,expiresIn: freezed == expiresIn ? _self.expiresIn : expiresIn // ignore: cast_nullable_to_non_nullable
|
||||
as String?,scope: freezed == scope ? _self.scope : scope // ignore: cast_nullable_to_non_nullable
|
||||
as String?,expireTime: freezed == expireTime ? _self.expireTime : expireTime // ignore: cast_nullable_to_non_nullable
|
||||
as String?,mobile: freezed == mobile ? _self.mobile : mobile // ignore: cast_nullable_to_non_nullable
|
||||
as String?,fullname: freezed == fullname ? _self.fullname : fullname // ignore: cast_nullable_to_non_nullable
|
||||
as String?,firstname: freezed == firstname ? _self.firstname : firstname // ignore: cast_nullable_to_non_nullable
|
||||
as String?,lastname: freezed == lastname ? _self.lastname : lastname // ignore: cast_nullable_to_non_nullable
|
||||
as String?,city: freezed == city ? _self.city : city // ignore: cast_nullable_to_non_nullable
|
||||
as String?,province: freezed == province ? _self.province : province // ignore: cast_nullable_to_non_nullable
|
||||
as String?,nationalCode: freezed == nationalCode ? _self.nationalCode : nationalCode // ignore: cast_nullable_to_non_nullable
|
||||
as String?,nationalId: freezed == nationalId ? _self.nationalId : nationalId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,birthday: freezed == birthday ? _self.birthday : birthday // ignore: cast_nullable_to_non_nullable
|
||||
as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable
|
||||
as String?,baseOrder: freezed == baseOrder ? _self.baseOrder : baseOrder // ignore: cast_nullable_to_non_nullable
|
||||
as int?,role: freezed == role ? _self._role : role // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -0,0 +1,47 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'user_profile_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_UserProfileModel _$UserProfileModelFromJson(Map<String, dynamic> json) =>
|
||||
_UserProfileModel(
|
||||
accessToken: json['access_token'] as String?,
|
||||
expiresIn: json['expires_in'] as String?,
|
||||
scope: json['scope'] as String?,
|
||||
expireTime: json['expire_time'] as String?,
|
||||
mobile: json['mobile'] as String?,
|
||||
fullname: json['fullname'] as String?,
|
||||
firstname: json['firstname'] as String?,
|
||||
lastname: json['lastname'] as String?,
|
||||
city: json['city'] as String?,
|
||||
province: json['province'] as String?,
|
||||
nationalCode: json['national_code'] as String?,
|
||||
nationalId: json['national_id'] as String?,
|
||||
birthday: json['birthday'] as String?,
|
||||
image: json['image'] as String?,
|
||||
baseOrder: (json['base_order'] as num?)?.toInt(),
|
||||
role: (json['role'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$UserProfileModelToJson(_UserProfileModel instance) =>
|
||||
<String, dynamic>{
|
||||
'access_token': instance.accessToken,
|
||||
'expires_in': instance.expiresIn,
|
||||
'scope': instance.scope,
|
||||
'expire_time': instance.expireTime,
|
||||
'mobile': instance.mobile,
|
||||
'fullname': instance.fullname,
|
||||
'firstname': instance.firstname,
|
||||
'lastname': instance.lastname,
|
||||
'city': instance.city,
|
||||
'province': instance.province,
|
||||
'national_code': instance.nationalCode,
|
||||
'national_id': instance.nationalId,
|
||||
'birthday': instance.birthday,
|
||||
'image': instance.image,
|
||||
'base_order': instance.baseOrder,
|
||||
'role': instance.role,
|
||||
};
|
||||
@@ -1,12 +1,11 @@
|
||||
|
||||
import 'package:rasadyar_auth/data/models/response/user_info/user_info_model.dart';
|
||||
|
||||
import '../models/response/auth/auth_response_model.dart';
|
||||
import '../models/response/captcha/captcha_response_model.dart';
|
||||
import '../models/response/user_profile_model/user_profile_model.dart';
|
||||
|
||||
abstract class AuthRepository {
|
||||
Future<AuthResponseModel?> login({
|
||||
required Map<String, dynamic> authRequest,
|
||||
});
|
||||
Future<UserProfileModel?> login({required Map<String, dynamic> authRequest});
|
||||
|
||||
Future<CaptchaResponseModel?> captcha();
|
||||
|
||||
@@ -14,10 +13,9 @@ abstract class AuthRepository {
|
||||
|
||||
Future<bool> hasAuthenticated();
|
||||
|
||||
|
||||
Future<AuthResponseModel?> loginWithRefreshToken({
|
||||
required Map<String, dynamic> authRequest,
|
||||
});
|
||||
|
||||
|
||||
Future<UserInfoModel?> getUserInfo(String phoneNumber);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:rasadyar_auth/data/models/response/user_info/user_info_model.dart';
|
||||
import 'package:rasadyar_auth/data/models/response/user_profile_model/user_profile_model.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
import '../models/response/auth/auth_response_model.dart';
|
||||
@@ -11,13 +13,13 @@ class AuthRepositoryImpl implements AuthRepository {
|
||||
AuthRepositoryImpl(this._httpClient);
|
||||
|
||||
@override
|
||||
Future<AuthResponseModel?> login({
|
||||
Future<UserProfileModel?> login({
|
||||
required Map<String, dynamic> authRequest,
|
||||
}) async {
|
||||
var res = await _httpClient.post<AuthResponseModel>(
|
||||
'$_BASE_URL/login/',
|
||||
var res = await _httpClient.post<UserProfileModel?>(
|
||||
'/api/login/',
|
||||
data: authRequest,
|
||||
fromJson: AuthResponseModel.fromJson,
|
||||
fromJson: UserProfileModel.fromJson,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
);
|
||||
return res.data;
|
||||
@@ -59,4 +61,19 @@ class AuthRepositoryImpl implements AuthRepository {
|
||||
|
||||
return response.data ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserInfoModel?> getUserInfo(String phoneNumber) async {
|
||||
var res = await _httpClient.post<UserInfoModel?>(
|
||||
'https://userbackend.rasadyaar.ir/api/send_otp/',
|
||||
data: {
|
||||
"mobile": phoneNumber,
|
||||
"state": ""
|
||||
},
|
||||
fromJson: UserInfoModel.fromJson,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
);
|
||||
return res.data;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_auth/data/di/auth_di.dart';
|
||||
import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart';
|
||||
import 'package:rasadyar_auth/data/services/token_storage_service.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
@@ -14,7 +14,7 @@ class AuthMiddleware extends GetMiddleware {
|
||||
final accessToken = tokenService.accessToken.value;
|
||||
|
||||
if (refreshToken == null || accessToken == null) {
|
||||
return RouteSettings(name: AuthPaths.moduleList);
|
||||
return RouteSettings(name: AuthPaths.auth, arguments: Module.chicken);
|
||||
}
|
||||
return super.redirect(route);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ import 'package:rasadyar_auth/hive_registrar.g.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class TokenStorageService extends GetxService {
|
||||
static const String _boxName = 'secureBox';
|
||||
static const String _tokenBoxName = 'TokenBox';
|
||||
static const String _appBoxName = 'AppBox';
|
||||
static const String _accessTokenKey = 'accessToken';
|
||||
static const String _refreshTokenKey = 'refreshToken';
|
||||
static const String _baseUrlKey = 'baseUrl';
|
||||
static const String _apiKey = 'apiKey';
|
||||
static const String _moduleKey = 'moduleSelected';
|
||||
|
||||
final FlutterSecureStorage _secureStorage = FlutterSecureStorage();
|
||||
@@ -15,6 +18,7 @@ class TokenStorageService extends GetxService {
|
||||
|
||||
RxnString accessToken = RxnString();
|
||||
RxnString refreshToken = RxnString();
|
||||
RxnString baseurl = RxnString();
|
||||
Rxn<Module> appModule = Rxn(null);
|
||||
|
||||
Future<void> init() async {
|
||||
@@ -22,41 +26,61 @@ class TokenStorageService extends GetxService {
|
||||
Hive.registerAdapters();
|
||||
|
||||
final String? encryptedKey = await _secureStorage.read(key: 'hive_enc_key');
|
||||
final encryptionKey = encryptedKey != null ? base64Url.decode(encryptedKey) : Hive.generateSecureKey();
|
||||
final encryptionKey = encryptedKey != null
|
||||
? base64Url.decode(encryptedKey)
|
||||
: Hive.generateSecureKey();
|
||||
|
||||
if (encryptedKey == null) {
|
||||
await _secureStorage.write(key: 'hive_enc_key', value: base64UrlEncode(encryptionKey));
|
||||
}
|
||||
|
||||
await _localStorage.init();
|
||||
await _localStorage.openBox(_boxName, encryptionCipher: HiveAesCipher(encryptionKey));
|
||||
await _localStorage.openBox(_tokenBoxName, encryptionCipher: HiveAesCipher(encryptionKey));
|
||||
await _localStorage.openBox(_appBoxName);
|
||||
|
||||
accessToken.value = _localStorage.read<String?>(boxName: _boxName, key: _accessTokenKey);
|
||||
refreshToken.value = _localStorage.read<String?>(boxName: _boxName, key: _refreshTokenKey);
|
||||
appModule.value = _localStorage.read<Module?>(boxName: _boxName, key: _moduleKey);
|
||||
accessToken.value = _localStorage.read<String?>(boxName: _tokenBoxName, key: _accessTokenKey);
|
||||
refreshToken.value = _localStorage.read<String?>(boxName: _tokenBoxName, key: _refreshTokenKey);
|
||||
appModule.value = _localStorage.read<Module?>(boxName: _appBoxName, key: _moduleKey);
|
||||
baseurl.value = _localStorage.read<String?>(boxName: _appBoxName, key: _baseUrlKey);
|
||||
}
|
||||
|
||||
Future<void> saveAccessToken(String token) async {
|
||||
await _localStorage.save(boxName: _boxName, key: _accessTokenKey, value: token);
|
||||
await _localStorage.save(boxName: _tokenBoxName, key: _accessTokenKey, value: token);
|
||||
accessToken.value = token;
|
||||
accessToken.refresh();
|
||||
}
|
||||
|
||||
Future<void> saveRefreshToken(String token) async {
|
||||
await _localStorage.save(boxName: _boxName, key: _refreshTokenKey, value: token);
|
||||
await _localStorage.save(boxName: _tokenBoxName, key: _refreshTokenKey, value: token);
|
||||
refreshToken.value = token;
|
||||
refreshToken.refresh();
|
||||
}
|
||||
|
||||
Future<void> saveModule(Module input) async {
|
||||
await _localStorage.save(boxName: _boxName, key: _moduleKey, value: input);
|
||||
await _localStorage.save(boxName: _tokenBoxName, key: _moduleKey, value: input);
|
||||
appModule.value = input;
|
||||
appModule.refresh();
|
||||
}
|
||||
|
||||
Future<void> deleteTokens() async {
|
||||
await _localStorage.clear(_boxName);
|
||||
await _localStorage.clear(_tokenBoxName);
|
||||
accessToken.value = null;
|
||||
refreshToken.value = null;
|
||||
}
|
||||
|
||||
Future<void> saveBaseUrl(String url) async {
|
||||
await _localStorage.save(boxName: _appBoxName, key: _baseUrlKey, value: url);
|
||||
baseurl.value = url;
|
||||
baseurl.refresh();
|
||||
}
|
||||
|
||||
void getBaseUrl() {
|
||||
var url = _localStorage.read(boxName: _appBoxName, key: _baseUrlKey);
|
||||
baseurl.value = url;
|
||||
baseurl.refresh();
|
||||
}
|
||||
|
||||
Future<void> saveApiKey(String key) async {
|
||||
await _localStorage.save(boxName: _tokenBoxName, key: _apiKey, value: key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:rasadyar_auth/auth.dart';
|
||||
import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
import '../models/response/auth/auth_response_model.dart';
|
||||
import '../services/token_storage_service.dart';
|
||||
|
||||
Future<void> safeCall<T>({
|
||||
Future<T?> safeCall<T>({
|
||||
required AppAsyncCallback<T> call,
|
||||
Function(T result)? onSuccess,
|
||||
ErrorCallback? onError,
|
||||
@@ -18,13 +12,8 @@ Future<void> safeCall<T>({
|
||||
bool showSnackBar = false,
|
||||
Function()? onShowLoading,
|
||||
Function()? onHideLoading,
|
||||
Function()? onShowSuccessMessage,
|
||||
Function()? onShowErrorMessage,
|
||||
}) {
|
||||
final authRepository = diAuth.get<AuthRepositoryImpl>();
|
||||
TokenStorageService tokenStorageService = Get.find<TokenStorageService>();
|
||||
|
||||
return gSafeCall(
|
||||
return gSafeCall<T>(
|
||||
call: call,
|
||||
onSuccess: onSuccess,
|
||||
onError: onError,
|
||||
@@ -32,30 +21,7 @@ Future<void> safeCall<T>({
|
||||
showLoading: showLoading,
|
||||
showError: showError,
|
||||
showSuccess: showSuccess,
|
||||
showToast: showToast,
|
||||
showSnackBar: showSnackBar,
|
||||
onShowLoading: onShowLoading,
|
||||
onHideLoading: onHideLoading,
|
||||
onShowSuccessMessage: onShowSuccessMessage,
|
||||
onShowErrorMessage: onShowErrorMessage,
|
||||
retryOnAuthError: true,
|
||||
onTokenRefresh: () {
|
||||
var token = tokenStorageService.refreshToken.value;
|
||||
authRepository
|
||||
.loginWithRefreshToken(authRequest: {"refresh_token": token})
|
||||
.then((value) async {
|
||||
if (value is AuthResponseModel) {
|
||||
await tokenStorageService.saveAccessToken(value.access!);
|
||||
} else {
|
||||
throw Exception("Failed to refresh token");
|
||||
}
|
||||
})
|
||||
.catchError((error) {
|
||||
if (kDebugMode) {
|
||||
print('Error during token refresh: $error');
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,8 @@ import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart
|
||||
|
||||
extension HiveRegistrar on HiveInterface {
|
||||
void registerAdapters() {
|
||||
registerAdapter(UserLocalModelAdapter());
|
||||
registerAdapter(ModuleAdapter());
|
||||
|
||||
registerAdapter(UserLocalModelAdapter());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_auth/auth.dart';
|
||||
import 'package:rasadyar_auth/data/common/dio_error_handler.dart';
|
||||
import 'package:rasadyar_auth/data/models/request/login_request/login_request_model.dart';
|
||||
import 'package:rasadyar_auth/data/models/response/auth/auth_response_model.dart';
|
||||
import 'package:rasadyar_auth/data/models/response/user_info/user_info_model.dart';
|
||||
import 'package:rasadyar_auth/data/models/response/user_profile_model/user_profile_model.dart';
|
||||
import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart';
|
||||
import 'package:rasadyar_auth/data/services/token_storage_service.dart';
|
||||
import 'package:rasadyar_auth/data/utils/safe_call.dart';
|
||||
@@ -26,14 +27,14 @@ class AuthLogic extends GetxController {
|
||||
Rx<GlobalKey<FormState>> formKeySentOtp = GlobalKey<FormState>().obs;
|
||||
Rx<TextEditingController> usernameController = TextEditingController().obs;
|
||||
Rx<TextEditingController> passwordController = TextEditingController().obs;
|
||||
Rx<TextEditingController> phoneOtpNumberController =
|
||||
TextEditingController().obs;
|
||||
Rx<TextEditingController> phoneOtpNumberController = TextEditingController().obs;
|
||||
Rx<TextEditingController> otpCodeController = TextEditingController().obs;
|
||||
|
||||
var captchaController = Get.find<CaptchaWidgetLogic>();
|
||||
|
||||
RxnString phoneNumber = RxnString(null);
|
||||
RxBool isLoading = false.obs;
|
||||
RxBool isDisabled = true.obs;
|
||||
TokenStorageService tokenStorageService = Get.find<TokenStorageService>();
|
||||
|
||||
Rx<AuthType> authType = AuthType.useAndPass.obs;
|
||||
@@ -70,15 +71,11 @@ class AuthLogic extends GetxController {
|
||||
return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
iLog('module111 : ${_module.toString()}');
|
||||
iLog('module selected : ${_module.toString()}');
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -88,8 +85,7 @@ class AuthLogic extends GetxController {
|
||||
}
|
||||
|
||||
bool _isFormValid() {
|
||||
final isCaptchaValid =
|
||||
captchaController.formKey.currentState?.validate() ?? false;
|
||||
final isCaptchaValid = captchaController.formKey.currentState?.validate() ?? false;
|
||||
final isFormValid = formKey.currentState?.validate() ?? false;
|
||||
return isCaptchaValid && isFormValid;
|
||||
}
|
||||
@@ -108,7 +104,7 @@ class AuthLogic extends GetxController {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> submitLoginForm() async {
|
||||
/*Future<void> submitLoginForm() async {
|
||||
if (!_isFormValid()) return;
|
||||
iLog('module222 : ${_module.toString()}');
|
||||
final loginRequestModel = _buildLoginRequest();
|
||||
@@ -128,5 +124,52 @@ class AuthLogic extends GetxController {
|
||||
},
|
||||
);
|
||||
isLoading.value = false;
|
||||
}*/
|
||||
|
||||
Future<void> submitLoginForm2() async {
|
||||
if (!_isFormValid()) return;
|
||||
AuthRepositoryImpl authTmp = diAuth.get<AuthRepositoryImpl>(instanceName: 'newUrl');
|
||||
isLoading.value = true;
|
||||
await safeCall<UserProfileModel?>(
|
||||
call: () => authTmp.login(
|
||||
authRequest: {
|
||||
"username": phoneNumberController.value.text,
|
||||
"password": passwordController.value.text,
|
||||
},
|
||||
),
|
||||
onSuccess: (result) async {
|
||||
await tokenStorageService.saveModule(_module);
|
||||
await tokenStorageService.saveAccessToken(result?.accessToken ?? '');
|
||||
await tokenStorageService.saveRefreshToken(result?.accessToken ?? '');
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
if (error is DioException) {
|
||||
diAuth.get<DioErrorHandler>().handle(error);
|
||||
}
|
||||
captchaController.getCaptcha();
|
||||
},
|
||||
);
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getUserInfo(String value) async {
|
||||
isLoading.value = true;
|
||||
await safeCall<UserInfoModel?>(
|
||||
call: () async => await authRepository.getUserInfo(value),
|
||||
onSuccess: (result) async {
|
||||
if (result != null) {
|
||||
await newSetupAuthDI(result.backend ?? '');
|
||||
await tokenStorageService.saveApiKey(result.apiKey ?? '');
|
||||
await tokenStorageService.saveBaseUrl(result.backend ?? '');
|
||||
}
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
if (error is DioException) {
|
||||
diAuth.get<DioErrorHandler>().handle(error);
|
||||
}
|
||||
captchaController.getCaptcha();
|
||||
},
|
||||
);
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,28 +27,31 @@ class AuthPage extends GetView<AuthLogic> {
|
||||
}
|
||||
}, controller.authType),
|
||||
|
||||
SizedBox(height: 50),
|
||||
SizedBox(height: 20),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'مطالعه بیانیه ',
|
||||
style: AppFonts.yekan14.copyWith(
|
||||
color: AppColor.darkGreyDark,
|
||||
),
|
||||
style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyDark),
|
||||
),
|
||||
TextSpan(
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {},
|
||||
..onTap = () {
|
||||
Get.bottomSheet(
|
||||
privacyPolicyWidget(),
|
||||
isScrollControlled: true,
|
||||
enableDrag: true,
|
||||
ignoreSafeArea: false,
|
||||
);
|
||||
},
|
||||
text: 'حریم خصوصی',
|
||||
style: AppFonts.yekan14.copyWith(
|
||||
color: AppColor.blueNormal,
|
||||
),
|
||||
style: AppFonts.yekan16.copyWith(color: AppColor.blueNormal),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 18),
|
||||
/* SizedBox(height: 18),
|
||||
|
||||
ObxValue((types) {
|
||||
return RichText(
|
||||
@@ -80,7 +83,7 @@ class AuthPage extends GetView<AuthLogic> {
|
||||
],
|
||||
),
|
||||
);
|
||||
}, controller.authType),
|
||||
}, controller.authType),*/
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -92,120 +95,201 @@ class AuthPage extends GetView<AuthLogic> {
|
||||
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 50),
|
||||
child: Form(
|
||||
key: controller.formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
ObxValue(
|
||||
(phoneController) =>
|
||||
RTextField(
|
||||
label: 'نام کاربری',
|
||||
maxLength: 11,
|
||||
maxLines: 1,
|
||||
controller: phoneController.value,
|
||||
keyboardType: TextInputType.text,
|
||||
initText: phoneController.value.text,
|
||||
onChanged: (value) {
|
||||
phoneController.value.text = value;
|
||||
phoneController.refresh();
|
||||
},
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
|
||||
child: Assets.vec.callSvg.svg(
|
||||
width: 12,
|
||||
height: 12,
|
||||
),
|
||||
),
|
||||
suffixIcon:
|
||||
phoneController.value.text
|
||||
.trim()
|
||||
.isNotEmpty
|
||||
? clearButton(() {
|
||||
phoneController.value.clear();
|
||||
phoneController.refresh();
|
||||
})
|
||||
: null,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '⚠️ شماره موبایل را وارد کنید';
|
||||
}
|
||||
/*else if (value.length < 11) {
|
||||
return '⚠️ شماره موبایل باید 11 رقم باشد';
|
||||
}*/
|
||||
return null;
|
||||
},
|
||||
style: AppFonts.yekan13,
|
||||
errorStyle: AppFonts.yekan13.copyWith(
|
||||
color: AppColor.redNormal,
|
||||
),
|
||||
labelStyle: AppFonts.yekan13,
|
||||
boxConstraints: const BoxConstraints(
|
||||
maxHeight: 40,
|
||||
minHeight: 40,
|
||||
maxWidth: 40,
|
||||
minWidth: 40,
|
||||
),
|
||||
),
|
||||
controller.usernameController,
|
||||
),
|
||||
const SizedBox(height: 26),
|
||||
ObxValue(
|
||||
(passwordController) =>
|
||||
RTextField(
|
||||
label: 'رمز عبور',
|
||||
filled: false,
|
||||
controller: passwordController.value,
|
||||
variant: RTextFieldVariant.password,
|
||||
initText: passwordController.value.text,
|
||||
onChanged: (value) {
|
||||
passwordController.refresh();
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '⚠️ رمز عبور را وارد کنید';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: AppFonts.yekan13,
|
||||
errorStyle: AppFonts.yekan13.copyWith(
|
||||
color: AppColor.redNormal,
|
||||
),
|
||||
labelStyle: AppFonts.yekan13,
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
|
||||
child: Assets.vec.keySvg.svg(
|
||||
width: 12,
|
||||
height: 12,
|
||||
),
|
||||
),
|
||||
boxConstraints: const BoxConstraints(
|
||||
maxHeight: 34,
|
||||
minHeight: 34,
|
||||
maxWidth: 34,
|
||||
minWidth: 34,
|
||||
),
|
||||
),
|
||||
controller.passwordController,
|
||||
),
|
||||
SizedBox(height: 26),
|
||||
CaptchaWidget(),
|
||||
SizedBox(height: 23),
|
||||
ObxValue((data) {
|
||||
return RElevated(
|
||||
text: 'ورود',
|
||||
isLoading: data.value,
|
||||
onPressed: () async {
|
||||
await controller.submitLoginForm();
|
||||
child: AutofillGroup(
|
||||
child: Column(
|
||||
children: [
|
||||
RTextField(
|
||||
label: 'نام کاربری',
|
||||
maxLength: 11,
|
||||
maxLines: 1,
|
||||
controller: controller.phoneNumberController.value,
|
||||
keyboardType: TextInputType.number,
|
||||
initText: controller.phoneNumberController.value.text,
|
||||
autofillHints: [AutofillHints.username],
|
||||
onChanged: (value) async {
|
||||
controller.phoneNumberController.value.text = value;
|
||||
controller.phoneNumberController.refresh();
|
||||
if (value.length == 11) {
|
||||
await controller.getUserInfo(value);
|
||||
}
|
||||
},
|
||||
width: Get.width,
|
||||
height: 48,
|
||||
);
|
||||
}, controller.isLoading),
|
||||
],
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
|
||||
child: Assets.vec.callSvg.svg(width: 12, height: 12),
|
||||
),
|
||||
suffixIcon: controller.phoneNumberController.value.text.trim().isNotEmpty
|
||||
? clearButton(() {
|
||||
controller.phoneNumberController.value.clear();
|
||||
controller.phoneNumberController.refresh();
|
||||
})
|
||||
: null,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '⚠️ شماره موبایل را وارد کنید';
|
||||
} else if (value.length < 11) {
|
||||
return '⚠️ شماره موبایل باید 11 رقم باشد';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: AppFonts.yekan13,
|
||||
errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
|
||||
labelStyle: AppFonts.yekan13,
|
||||
boxConstraints: const BoxConstraints(
|
||||
maxHeight: 40,
|
||||
minHeight: 40,
|
||||
maxWidth: 40,
|
||||
minWidth: 40,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 26),
|
||||
ObxValue(
|
||||
(passwordController) => RTextField(
|
||||
label: 'رمز عبور',
|
||||
filled: false,
|
||||
obscure: true,
|
||||
controller: passwordController.value,
|
||||
autofillHints: [AutofillHints.password],
|
||||
variant: RTextFieldVariant.password,
|
||||
initText: passwordController.value.text,
|
||||
onChanged: (value) {
|
||||
passwordController.refresh();
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '⚠️ رمز عبور را وارد کنید';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: AppFonts.yekan13,
|
||||
errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
|
||||
labelStyle: AppFonts.yekan13,
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
|
||||
child: Assets.vec.keySvg.svg(width: 12, height: 12),
|
||||
),
|
||||
boxConstraints: const BoxConstraints(
|
||||
maxHeight: 34,
|
||||
minHeight: 34,
|
||||
maxWidth: 34,
|
||||
minWidth: 34,
|
||||
),
|
||||
),
|
||||
controller.passwordController,
|
||||
),
|
||||
SizedBox(height: 26),
|
||||
CaptchaWidget(),
|
||||
SizedBox(height: 23),
|
||||
|
||||
Obx(() {
|
||||
return RElevated(
|
||||
text: 'ورود',
|
||||
isLoading: controller.isLoading.value,
|
||||
onPressed: controller.isDisabled.value
|
||||
? null
|
||||
: () async {
|
||||
await controller.submitLoginForm2();
|
||||
},
|
||||
width: Get.width,
|
||||
height: 48,
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
Widget privacyPolicyWidget() {
|
||||
return BaseBottomSheet(
|
||||
child: Column(
|
||||
spacing: 5,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(8.w),
|
||||
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColor.darkGreyLight, width: 1),
|
||||
),
|
||||
child: Column(
|
||||
spacing: 3,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'بيانيه حريم خصوصی',
|
||||
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
|
||||
),
|
||||
Text(
|
||||
'اطلاعات مربوط به هر شخص، حریم خصوصی وی محسوب میشود. حفاظت و حراست از اطلاعات شخصی در سامانه رصد یار، نه تنها موجب حفظ امنیت کاربران میشود، بلکه باعث اعتماد بیشتر و مشارکت آنها در فعالیتهای جاری میگردد. هدف از این بیانیه، آگاه ساختن شما درباره ی نوع و نحوه ی استفاده از اطلاعاتی است که در هنگام استفاده از سامانه رصد یار ، از جانب شما دریافت میگردد. شرکت هوشمند سازان خود را ملزم به رعایت حریم خصوصی همه شهروندان و کاربران سامانه دانسته و آن دسته از اطلاعات کاربران را که فقط به منظور ارائه خدمات کفایت میکند، دریافت کرده و از انتشار آن یا در اختیار قرار دادن آن به دیگران خودداری مینماید.',
|
||||
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(8.w),
|
||||
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColor.darkGreyLight, width: 1),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 4,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'چگونگی جمع آوری و استفاده از اطلاعات کاربران',
|
||||
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
|
||||
),
|
||||
Text(
|
||||
'''الف: اطلاعاتی که شما خود در اختيار این سامانه قرار میدهيد، شامل موارد زيرهستند:
|
||||
اقلام اطلاعاتی شامل شماره تلفن همراه، تاریخ تولد، کد پستی و کد ملی کاربران را دریافت مینماییم که از این اقلام، صرفا جهت احراز هویت کاربران استفاده خواهد شد.
|
||||
ب: برخی اطلاعات ديگر که به صورت خودکار از شما دريافت میشود شامل موارد زير میباشد:
|
||||
⦁ دستگاهی که از طریق آن سامانه رصد یار را مشاهده مینمایید( تلفن همراه، تبلت، رایانه).
|
||||
⦁ نام و نسخه سیستم عامل و browser کامپیوتر شما.
|
||||
⦁ اطلاعات صفحات بازدید شده.
|
||||
⦁ تعداد بازدیدهای روزانه در درگاه.
|
||||
⦁ هدف ما از دریافت این اطلاعات استفاده از آنها در تحلیل عملکرد کاربران درگاه می باشد تا بتوانیم در خدمت رسانی بهتر عمل کنیم.
|
||||
''',
|
||||
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(8.w),
|
||||
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColor.darkGreyLight, width: 1),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 4,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'امنیت اطلاعات',
|
||||
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
|
||||
),
|
||||
Text(
|
||||
'متعهدیم که امنیت اطلاعات شما را تضمین نماییم و برای جلوگیری از هر نوع دسترسی غیرمجاز و افشای اطلاعات شما از همه شیوههای لازم استفاده میکنیم تا امنیت اطلاعاتی را که به صورت آنلاین گردآوری میکنیم، حفظ شود. لازم به ذکر است در سامانه ما، ممکن است به سایت های دیگری لینک شوید، وقتی که شما از طریق این لینکها از سامانه ما خارج میشوید، توجه داشته باشید که ما بر دیگر سایت ها کنترل نداریم و سازمان تعهدی بر حفظ حریم شخصی آنان در سایت مقصد نخواهد داشت و مراجعه کنندگان میبایست به بیانیه حریم شخصی آن سایت ها مراجعه نمایند.',
|
||||
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
Widget sendCodeForm() {
|
||||
return ObxValue((data) {
|
||||
return Form(
|
||||
|
||||
@@ -7,6 +7,7 @@ class ModulesLogic extends GetxController {
|
||||
List<ModuleModel> moduleList=[
|
||||
ModuleModel(title: 'بازرسی', icon: Assets.icons.inspection.path, module: Module.inspection),
|
||||
ModuleModel(title: 'دام', icon: Assets.icons.liveStock.path, module: Module.liveStocks),
|
||||
ModuleModel(title: 'مرغ', icon: Assets.icons.liveStock.path, module: Module.chicken),
|
||||
];
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_auth/data/di/auth_di.dart';
|
||||
import 'package:rasadyar_auth/data/models/response/captcha/captcha_response_model.dart';
|
||||
import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart';
|
||||
import 'package:rasadyar_auth/data/utils/safe_call.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class CaptchaWidgetLogic extends GetxController with StateMixin<CaptchaResponseModel> {
|
||||
Rx<TextEditingController> textController = TextEditingController().obs;
|
||||
TextEditingController textController = TextEditingController();
|
||||
RxnString captchaKey = RxnString();
|
||||
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
AuthRepositoryImpl authRepository = diAuth.get<AuthRepositoryImpl>();
|
||||
final Random random = Random();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
@@ -20,22 +22,17 @@ class CaptchaWidgetLogic extends GetxController with StateMixin<CaptchaResponseM
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
textController.value.dispose();
|
||||
textController.clear();
|
||||
textController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<void> getCaptcha() async {
|
||||
change(null, status: RxStatus.loading());
|
||||
textController.value.clear();
|
||||
safeCall(
|
||||
call: () async => await authRepository.captcha(),
|
||||
onSuccess: (value) {
|
||||
captchaKey.value = value?.captchaKey;
|
||||
change(value, status: RxStatus.success());
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
change(null, status: RxStatus.error(error.toString()));
|
||||
},
|
||||
);
|
||||
textController.clear();
|
||||
await Future.delayed(Duration(milliseconds: 800));
|
||||
captchaKey.value = (random.nextInt(900000)+100000).toString();
|
||||
change(value, status: RxStatus.success());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_auth/presentation/pages/auth/logic.dart';
|
||||
import 'package:rasadyar_auth/presentation/widget/clear_button.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
@@ -16,73 +17,93 @@ class CaptchaWidget extends GetView<CaptchaWidgetLogic> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: controller.getCaptcha,
|
||||
child: Container(
|
||||
width: 135,
|
||||
height: 50,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.whiteNormalHover,
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: controller.obx(
|
||||
(state) =>
|
||||
Image.memory(
|
||||
base64Decode(state?.captchaImage ?? ''),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
onLoading: const Center(
|
||||
child: CupertinoActivityIndicator(color: AppColor.blueNormal),
|
||||
onTap: controller.getCaptcha,
|
||||
child: Container(
|
||||
width: 135,
|
||||
height: 50,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.whiteNormalHover,
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: controller.obx(
|
||||
(state) => Center(
|
||||
child: Text(
|
||||
controller.captchaKey.value ?? 'دوباره سعی کنید',
|
||||
style: AppFonts.yekan24Bold,
|
||||
),
|
||||
onError: (error) {
|
||||
return const Center(
|
||||
child: Text(
|
||||
'خطا در بارگذاری کد امنیتی',
|
||||
style: AppFonts.yekan13,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)),
|
||||
onLoading: const Center(
|
||||
child: CupertinoActivityIndicator(color: AppColor.blueNormal),
|
||||
),
|
||||
onError: (error) {
|
||||
return Center(
|
||||
child: Text('خطا ', style: AppFonts.yekan13.copyWith(color: Colors.red)),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Form(
|
||||
key: controller.formKey,
|
||||
autovalidateMode: AutovalidateMode.disabled,
|
||||
child: ObxValue((data) {
|
||||
return RTextField(
|
||||
label: 'کد امنیتی',
|
||||
controller: data.value,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
decimal: false,
|
||||
signed: false,
|
||||
),
|
||||
maxLines: 1,
|
||||
maxLength: 6,
|
||||
suffixIcon:
|
||||
(data.value.text
|
||||
.trim()
|
||||
.isNotEmpty ?? false)
|
||||
? clearButton(
|
||||
() => controller.textController.value.clear(),
|
||||
)
|
||||
: null,
|
||||
child: RTextField(
|
||||
label: 'کد امنیتی',
|
||||
controller: controller.textController,
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: false, signed: false),
|
||||
maxLines: 1,
|
||||
maxLength: 6,
|
||||
suffixIcon: (controller.textController.text.trim().isNotEmpty ?? false)
|
||||
? clearButton(() => controller.textController.clear())
|
||||
: null,
|
||||
|
||||
onSubmitted: (data) {},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'کد امنیتی را وارد کنید';
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'کد امنیتی را وارد کنید';
|
||||
} else if (controller.captchaKey.value != null &&
|
||||
controller.captchaKey.value != value) {
|
||||
return 'کد امنیتی اشتباه است';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onChanged: (pass) {
|
||||
if (pass.length == 6) {
|
||||
if (controller.formKey.currentState?.validate() ?? false) {
|
||||
Get.find<AuthLogic>().isDisabled.value = false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: AppFonts.yekan13,
|
||||
);
|
||||
}, controller.textController),
|
||||
}
|
||||
},
|
||||
style: AppFonts.yekan13,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CaptchaLinePainter extends CustomPainter {
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final random = Random();
|
||||
final paint1 = Paint()
|
||||
..color = Colors.deepOrange
|
||||
..strokeWidth = 2;
|
||||
final paint2 = Paint()
|
||||
..color = Colors.blue
|
||||
..strokeWidth = 2;
|
||||
|
||||
// First line: top-left to bottom-right
|
||||
canvas.drawLine(Offset(0, 0), Offset(size.width, size.height), paint1);
|
||||
|
||||
// Second line: bottom-left to top-right
|
||||
canvas.drawLine(Offset(0, size.height), Offset(size.width, 0), paint2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: rasadyar_auth
|
||||
description: "A new Flutter project."
|
||||
version: 1.0.2
|
||||
version: 1.0.3
|
||||
publish_to: 'none'
|
||||
|
||||
|
||||
@@ -15,17 +15,17 @@ dependencies:
|
||||
rasadyar_core:
|
||||
path: ../core
|
||||
##code generation
|
||||
freezed_annotation: ^3.0.0
|
||||
freezed_annotation: ^3.1.0
|
||||
json_annotation: ^4.9.0
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^5.0.0
|
||||
flutter_lints: ^6.0.0
|
||||
##code generation
|
||||
build_runner: ^2.4.15
|
||||
hive_ce_generator: ^1.9.1
|
||||
freezed: ^3.0.6
|
||||
json_serializable: ^6.9.4
|
||||
build_runner: ^2.6.0
|
||||
hive_ce_generator: ^1.9.3
|
||||
freezed: ^3.2.0
|
||||
json_serializable: ^6.10.0
|
||||
|
||||
##test
|
||||
mocktail: ^1.0.4
|
||||
|
||||
Reference in New Issue
Block a user