feat : new auth in chicken
This commit is contained in:
@@ -16,10 +16,11 @@ class CustomNavigationObserver extends NavigatorObserver {
|
|||||||
void didPush(Route route, Route? previousRoute) async {
|
void didPush(Route route, Route? previousRoute) async {
|
||||||
super.didPush(route, previousRoute);
|
super.didPush(route, previousRoute);
|
||||||
final routeName = route.settings.name;
|
final routeName = route.settings.name;
|
||||||
if (!_isWorkDone && routeName == ChickenRoutes.init) {
|
if (!_isWorkDone &&( routeName == ChickenRoutes.init || routeName == ChickenRoutes.auth)) {
|
||||||
_isWorkDone = true;
|
_isWorkDone = true;
|
||||||
setupChickenDI();
|
await setupChickenDI();
|
||||||
} else if (!_isWorkDone && (routeName == InspectionRoutes.init || routeName == InspectionRoutes.auth)) {
|
} else if (!_isWorkDone &&
|
||||||
|
(routeName == InspectionRoutes.init || routeName == InspectionRoutes.auth)) {
|
||||||
_isWorkDone = true;
|
_isWorkDone = true;
|
||||||
|
|
||||||
await setupInspectionDI();
|
await setupInspectionDI();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class ModulesLogic extends GetxController {
|
|||||||
|
|
||||||
List<ModuleModel> moduleList = [
|
List<ModuleModel> moduleList = [
|
||||||
ModuleModel(title: 'بازرسی', icon: Assets.icons.inspection.path, module: Module.inspection),
|
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.liveStocks),
|
||||||
ModuleModel(title: 'مرغ', icon: Assets.icons.liveStock.path, module: Module.chicken),
|
ModuleModel(title: 'مرغ', icon: Assets.icons.liveStock.path, module: Module.chicken),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:rasadyar_chicken/chicken.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
import 'package:rasadyar_inspection/inspection.dart';
|
import 'package:rasadyar_inspection/inspection.dart';
|
||||||
|
|
||||||
@@ -33,8 +34,9 @@ class ModulesPage extends GetView<ModulesLogic> {
|
|||||||
Get.toNamed(InspectionRoutes.init);
|
Get.toNamed(InspectionRoutes.init);
|
||||||
break;
|
break;
|
||||||
case Module.liveStocks:
|
case Module.liveStocks:
|
||||||
|
//TODO: Implement liveStocks module navigation
|
||||||
case Module.chicken:
|
case Module.chicken:
|
||||||
Get.toNamed(InspectionRoutes.init);
|
Get.toNamed(ChickenRoutes.init);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import 'package:rasadyar_chicken/chicken.dart';
|
import 'package:rasadyar_chicken/chicken.dart';
|
||||||
import 'package:rasadyar_chicken/data/datasource/local/chicken_local.dart';
|
|
||||||
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
|
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
import 'chicken_local.dart';
|
||||||
|
|
||||||
class ChickenLocalDataSourceImp implements ChickenLocalDataSource {
|
class ChickenLocalDataSourceImp implements ChickenLocalDataSource {
|
||||||
HiveLocalStorage local = diCore.get<HiveLocalStorage>();
|
HiveLocalStorage local = diCore.get<HiveLocalStorage>();
|
||||||
final String boxName = 'Chicken_Widley_Box';
|
final String boxName = 'Chicken_Widley_Box';
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:rasadyar_chicken/data/models/response/captcha/captcha_response_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
|
||||||
|
abstract class AuthRemoteDataSource {
|
||||||
|
Future<UserProfileModel?> login({required Map<String, dynamic> authRequest});
|
||||||
|
|
||||||
|
Future<void> logout();
|
||||||
|
|
||||||
|
Future<bool> hasAuthenticated();
|
||||||
|
|
||||||
|
Future<UserInfoModel?> getUserInfo(String phoneNumber);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
import 'auth_remote.dart';
|
||||||
|
|
||||||
|
class AuthRemoteDataSourceImp extends AuthRemoteDataSource {
|
||||||
|
final DioRemote _httpClient;
|
||||||
|
final String _BASE_URL = 'auth/api/v1/';
|
||||||
|
|
||||||
|
AuthRemoteDataSourceImp(this._httpClient);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<UserProfileModel?> login({required Map<String, dynamic> authRequest}) async {
|
||||||
|
var res = await _httpClient.post<UserProfileModel?>(
|
||||||
|
'/api/login/',
|
||||||
|
data: authRequest,
|
||||||
|
fromJson: UserProfileModel.fromJson,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
);
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> logout() {
|
||||||
|
// TODO: implement logout
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> hasAuthenticated() async {
|
||||||
|
final response = await _httpClient.get<bool>(
|
||||||
|
'$_BASE_URL/login/',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
);
|
||||||
|
|
||||||
|
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,4 +1,4 @@
|
|||||||
import 'package:rasadyar_chicken/data/datasource/remote/chicken_remote.dart';
|
|
||||||
import 'package:rasadyar_chicken/data/models/request/change_password/change_password_request_model.dart';
|
import 'package:rasadyar_chicken/data/models/request/change_password/change_password_request_model.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/request/conform_allocation/conform_allocation.dart';
|
import 'package:rasadyar_chicken/data/models/request/conform_allocation/conform_allocation.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/request/create_steward_free_bar/create_steward_free_bar.dart';
|
import 'package:rasadyar_chicken/data/models/request/create_steward_free_bar/create_steward_free_bar.dart';
|
||||||
@@ -24,6 +24,8 @@ import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_ar
|
|||||||
hide ProductModel;
|
hide ProductModel;
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
import 'chicken_remote.dart';
|
||||||
|
|
||||||
class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
|
class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource {
|
||||||
final DioRemote _httpClient;
|
final DioRemote _httpClient;
|
||||||
|
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
import 'package:rasadyar_chicken/data/datasource/local/chicken_local_imp.dart';
|
import 'package:rasadyar_chicken/chicken.dart';
|
||||||
import 'package:rasadyar_chicken/data/datasource/remote/chicken_remote_imp.dart';
|
import 'package:rasadyar_chicken/data/common/dio_error_handler.dart';
|
||||||
import 'package:rasadyar_chicken/data/repositories/chicken_repository_imp.dart';
|
import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote.dart';
|
||||||
import 'package:rasadyar_chicken/hive_registrar.g.dart';
|
import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote_imp.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
import 'package:rasadyar_chicken/data/repositories/auth/auth_repository_imp.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
GetIt diChicken = GetIt.instance;
|
GetIt diChicken = GetIt.instance;
|
||||||
|
|
||||||
Future<void> setupChickenDI() async {
|
Future<void> setupChickenDI() async {
|
||||||
|
diChicken.registerSingleton(DioErrorHandler());
|
||||||
var tokenService = Get.find<TokenStorageService>();
|
var tokenService = Get.find<TokenStorageService>();
|
||||||
Hive.registerAdapters();
|
|
||||||
diChicken.registerLazySingleton<ChickenLocalDataSourceImp>(() => ChickenLocalDataSourceImp());
|
|
||||||
diChicken.get<ChickenLocalDataSourceImp>().openBox();
|
|
||||||
|
|
||||||
diChicken.registerLazySingleton<AppInterceptor>(
|
diChicken.registerLazySingleton<AppInterceptor>(
|
||||||
() => AppInterceptor(
|
() => AppInterceptor(
|
||||||
@@ -24,32 +22,53 @@ Future<void> setupChickenDI() async {
|
|||||||
await tokenService.deleteTokens();
|
await tokenService.deleteTokens();
|
||||||
Get.offAllNamed(ChickenRoutes.auth, arguments: Module.chicken);
|
Get.offAllNamed(ChickenRoutes.auth, arguments: Module.chicken);
|
||||||
},
|
},
|
||||||
authArguments: Module.chicken,
|
|
||||||
),
|
),
|
||||||
instanceName: 'chickenInterceptor',
|
instanceName: 'chickenInterceptor',
|
||||||
);
|
);
|
||||||
|
|
||||||
tokenService.getBaseUrl();
|
diChicken.registerLazySingleton<DioRemote>(
|
||||||
|
() =>
|
||||||
diChicken.registerLazySingleton<DioRemote>(() {
|
DioRemote(interceptors: diChicken.get<AppInterceptor>(instanceName: 'chickenInterceptor')),
|
||||||
return DioRemote(
|
|
||||||
baseUrl: tokenService.baseurl.value,
|
|
||||||
interceptors: diChicken.get<AppInterceptor>(instanceName: 'chickenInterceptor'),
|
|
||||||
);
|
|
||||||
}, instanceName: 'chickenDioRemote');
|
|
||||||
|
|
||||||
final dioRemote = diChicken.get<DioRemote>(instanceName: 'chickenDioRemote');
|
|
||||||
|
|
||||||
await dioRemote.init();
|
|
||||||
|
|
||||||
diChicken.registerLazySingleton(() => ChickenRemoteDatasourceImp(dioRemote));
|
|
||||||
|
|
||||||
diChicken.registerLazySingleton<ChickenRepositoryImp>(
|
|
||||||
() => ChickenRepositoryImp(
|
|
||||||
local: diChicken.get<ChickenLocalDataSourceImp>(),
|
|
||||||
remote: diChicken.get<ChickenRemoteDatasourceImp>(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
diChicken.registerSingleton(ImagePicker());
|
final dioRemote = diChicken.get<DioRemote>();
|
||||||
|
await dioRemote.init();
|
||||||
|
|
||||||
|
diChicken.registerLazySingleton<AuthRemoteDataSourceImp>(
|
||||||
|
() => AuthRemoteDataSourceImp(diChicken.get<DioRemote>()),
|
||||||
|
);
|
||||||
|
|
||||||
|
diChicken.registerLazySingleton<AuthRepositoryImpl>(
|
||||||
|
() => AuthRepositoryImpl(diChicken.get<AuthRemoteDataSourceImp>()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> newSetupAuthDI(String newUrl) async {
|
||||||
|
var tokenService = Get.find<TokenStorageService>();
|
||||||
|
if (tokenService.baseurl.value == null) {
|
||||||
|
await tokenService.saveBaseUrl(newUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diChicken.isRegistered<DioRemote>()) {
|
||||||
|
await diChicken.unregister<DioRemote>();
|
||||||
|
diChicken.registerLazySingleton<DioRemote>(
|
||||||
|
() => DioRemote(baseUrl: newUrl, interceptors: diChicken.get<AppInterceptor>()),
|
||||||
|
);
|
||||||
|
final dioRemote = diChicken.get<DioRemote>();
|
||||||
|
await dioRemote.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diChicken.isRegistered<AuthRemoteDataSource>()) {
|
||||||
|
await diChicken.unregister<AuthRemoteDataSource>();
|
||||||
|
diChicken.registerLazySingleton<AuthRemoteDataSourceImp>(
|
||||||
|
() => AuthRemoteDataSourceImp(diChicken.get<DioRemote>()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diChicken.isRegistered<AuthRepositoryImpl>()) {
|
||||||
|
await diChicken.unregister<AuthRepositoryImpl>();
|
||||||
|
diChicken.registerLazySingleton<AuthRepositoryImpl>(
|
||||||
|
() => AuthRepositoryImpl(diChicken.get<AuthRemoteDataSource>()),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
|
||||||
|
abstract class AuthRepository {
|
||||||
|
Future<UserProfileModel?> login({required Map<String, dynamic> authRequest});
|
||||||
|
|
||||||
|
Future<void> logout();
|
||||||
|
|
||||||
|
Future<bool> hasAuthenticated();
|
||||||
|
|
||||||
|
Future<UserInfoModel?> getUserInfo(String phoneNumber);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
|
||||||
|
import 'auth_repository.dart';
|
||||||
|
|
||||||
|
class AuthRepositoryImpl implements AuthRepository {
|
||||||
|
final AuthRemoteDataSource authRemote;
|
||||||
|
|
||||||
|
AuthRepositoryImpl(this.authRemote);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<UserProfileModel?> login({required Map<String, dynamic> authRequest}) async =>
|
||||||
|
await authRemote.login(authRequest: authRequest);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> logout() async => await authRemote.logout();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> hasAuthenticated() async => await authRemote.hasAuthenticated();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<UserInfoModel?> getUserInfo(String phoneNumber) async =>
|
||||||
|
await authRemote.getUserInfo(phoneNumber);
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_ar
|
|||||||
hide ProductModel;
|
hide ProductModel;
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
import '../models/request/create_steward_free_bar/create_steward_free_bar.dart';
|
import '../../models/request/create_steward_free_bar/create_steward_free_bar.dart';
|
||||||
|
|
||||||
abstract class ChickenRepository {
|
abstract class ChickenRepository {
|
||||||
//region Remote
|
//region Remote
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:rasadyar_chicken/data/datasource/local/chicken_local_imp.dart';
|
import 'package:rasadyar_chicken/data/data_source/local/chicken_local_imp.dart';
|
||||||
import 'package:rasadyar_chicken/data/datasource/remote/chicken_remote_imp.dart';
|
import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote_imp.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
|
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/request/change_password/change_password_request_model.dart';
|
import 'package:rasadyar_chicken/data/models/request/change_password/change_password_request_model.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/request/conform_allocation/conform_allocation.dart';
|
import 'package:rasadyar_chicken/data/models/request/conform_allocation/conform_allocation.dart';
|
||||||
165
packages/chicken/lib/presentation/pages/auth/logic.dart
Normal file
165
packages/chicken/lib/presentation/pages/auth/logic.dart
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/common/dio_error_handler.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/request/login_request/login_request_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/repositories/auth/auth_repository_imp.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/widget/captcha/logic.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
enum AuthType { useAndPass, otp }
|
||||||
|
|
||||||
|
enum AuthStatus { init }
|
||||||
|
|
||||||
|
enum OtpStatus { init, sent, verified, reSend }
|
||||||
|
|
||||||
|
class AuthLogic extends GetxController with GetTickerProviderStateMixin {
|
||||||
|
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
late AnimationController _textAnimationController;
|
||||||
|
late Animation<double> textAnimation;
|
||||||
|
RxBool showCard = false.obs;
|
||||||
|
|
||||||
|
Rx<GlobalKey<FormState>> formKeyOtp = GlobalKey<FormState>().obs;
|
||||||
|
Rx<GlobalKey<FormState>> formKeySentOtp = GlobalKey<FormState>().obs;
|
||||||
|
Rx<TextEditingController> usernameController = TextEditingController().obs;
|
||||||
|
Rx<TextEditingController> passwordController = 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;
|
||||||
|
Rx<AuthStatus> authStatus = AuthStatus.init.obs;
|
||||||
|
Rx<OtpStatus> otpStatus = OtpStatus.init.obs;
|
||||||
|
|
||||||
|
RxInt secondsRemaining = 120.obs;
|
||||||
|
Timer? _timer;
|
||||||
|
|
||||||
|
AuthRepositoryImpl authRepository = diChicken.get<AuthRepositoryImpl>();
|
||||||
|
|
||||||
|
final Module _module = Get.arguments;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
|
||||||
|
_textAnimationController =
|
||||||
|
AnimationController(vsync: this, duration: const Duration(milliseconds: 1200))
|
||||||
|
..repeat(reverse: true, count: 2).whenComplete(() {
|
||||||
|
showCard.value = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
textAnimation = CurvedAnimation(parent: _textAnimationController, curve: Curves.easeInOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onReady() {
|
||||||
|
super.onReady();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
_timer?.cancel();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void startTimer() {
|
||||||
|
_timer?.cancel();
|
||||||
|
secondsRemaining.value = 120;
|
||||||
|
|
||||||
|
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
|
if (secondsRemaining.value > 0) {
|
||||||
|
secondsRemaining.value--;
|
||||||
|
} else {
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopTimer() {
|
||||||
|
_timer?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
String get timeFormatted {
|
||||||
|
final minutes = secondsRemaining.value ~/ 60;
|
||||||
|
final seconds = secondsRemaining.value % 60;
|
||||||
|
return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isFormValid() {
|
||||||
|
final isCaptchaValid = captchaController.formKey.currentState?.validate() ?? false;
|
||||||
|
final isFormValid = formKey.currentState?.validate() ?? false;
|
||||||
|
return isCaptchaValid && isFormValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginRequestModel _buildLoginRequest() {
|
||||||
|
final phone = usernameController.value.text;
|
||||||
|
final pass = passwordController.value.text;
|
||||||
|
final code = captchaController.textController.value.text;
|
||||||
|
final key = captchaController.captchaKey.value;
|
||||||
|
|
||||||
|
return LoginRequestModel.createWithCaptcha(
|
||||||
|
username: phone,
|
||||||
|
password: pass,
|
||||||
|
captchaCode: code,
|
||||||
|
captchaKey: key!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> submitLoginForm() async {
|
||||||
|
if (!_isFormValid()) return;
|
||||||
|
AuthRepositoryImpl authTmp = diChicken.get<AuthRepositoryImpl>(instanceName: 'newUrl');
|
||||||
|
isLoading.value = true;
|
||||||
|
await safeCall<UserProfileModel?>(
|
||||||
|
call: () => authTmp.login(
|
||||||
|
authRequest: {
|
||||||
|
"username": usernameController.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) {
|
||||||
|
diChicken.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) {
|
||||||
|
diChicken.get<DioErrorHandler>().handle(error);
|
||||||
|
}
|
||||||
|
captchaController.getCaptcha();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
543
packages/chicken/lib/presentation/pages/auth/view.dart
Normal file
543
packages/chicken/lib/presentation/pages/auth/view.dart
Normal file
@@ -0,0 +1,543 @@
|
|||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/widget/captcha/view.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
import 'logic.dart';
|
||||||
|
|
||||||
|
class AuthPage extends GetView<AuthLogic> {
|
||||||
|
const AuthPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
|
||||||
|
children: [
|
||||||
|
Assets.vec.bgAuthSvg.svg(fit: BoxFit.fill),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10.r),
|
||||||
|
child: FadeTransition(
|
||||||
|
opacity: controller.textAnimation,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
spacing: 12,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'به سامانه رصدیار خوش آمدید!',
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
style: AppFonts.yekan25Bold.copyWith(color: Colors.white),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'سامانه رصد و پایش زنجیره تامین، تولید و توزیع کالا های اساسی',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppFonts.yekan16.copyWith(color: Colors.white),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Obx(() {
|
||||||
|
final screenHeight = MediaQuery.of(context).size.height;
|
||||||
|
final targetTop = (screenHeight - 676) / 2;
|
||||||
|
|
||||||
|
return AnimatedPositioned(
|
||||||
|
duration: const Duration(milliseconds: 1200),
|
||||||
|
curve: Curves.linear,
|
||||||
|
top: controller.showCard.value ? targetTop : screenHeight,
|
||||||
|
left: 10.r,
|
||||||
|
right: 10.r,
|
||||||
|
child: Container(
|
||||||
|
width: 381.w,
|
||||||
|
height: 676.h,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(40),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 50.h),
|
||||||
|
LogoWidget(),
|
||||||
|
SizedBox(height: 20.h),
|
||||||
|
useAndPassFrom(),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: 'مطالعه بیانیه ',
|
||||||
|
style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyDark),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
recognizer: TapGestureRecognizer()
|
||||||
|
..onTap = () {
|
||||||
|
Get.bottomSheet(
|
||||||
|
privacyPolicyWidget(),
|
||||||
|
isScrollControlled: true,
|
||||||
|
enableDrag: true,
|
||||||
|
ignoreSafeArea: false,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
text: 'حریم خصوصی',
|
||||||
|
style: AppFonts.yekan16.copyWith(color: AppColor.blueNormal),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget useAndPassFrom() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 30.r),
|
||||||
|
child: Form(
|
||||||
|
key: controller.formKey,
|
||||||
|
child: AutofillGroup(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
RTextField(
|
||||||
|
label: 'نام کاربری',
|
||||||
|
maxLength: 11,
|
||||||
|
maxLines: 1,
|
||||||
|
controller: controller.usernameController.value,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
initText: controller.usernameController.value.text,
|
||||||
|
autofillHints: [AutofillHints.username],
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide: BorderSide(color: AppColor.textColor, width: 1),
|
||||||
|
),
|
||||||
|
onChanged: (value) async {
|
||||||
|
controller.usernameController.value.text = value;
|
||||||
|
if (value.length == 11) {
|
||||||
|
await controller.getUserInfo(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
prefixIcon: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
|
||||||
|
child: Assets.vec.callSvg.svg(width: 12, height: 12),
|
||||||
|
),
|
||||||
|
suffixIcon: controller.usernameController.value.text.trim().isNotEmpty
|
||||||
|
? clearButton(() {
|
||||||
|
controller.usernameController.value.clear();
|
||||||
|
controller.usernameController.refresh();
|
||||||
|
})
|
||||||
|
: null,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return '⚠️ شماره موبایل را وارد کنید';
|
||||||
|
} else if (value.length < 10) {
|
||||||
|
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,
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide: BorderSide(color: AppColor.textColor, width: 1),
|
||||||
|
),
|
||||||
|
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.submitLoginForm();
|
||||||
|
},
|
||||||
|
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(
|
||||||
|
key: data.value,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 50),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 26),
|
||||||
|
ObxValue((phoneController) {
|
||||||
|
return TextFormField(
|
||||||
|
controller: phoneController.value,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
gapPadding: 11,
|
||||||
|
),
|
||||||
|
labelText: 'شماره موبایل',
|
||||||
|
labelStyle: AppFonts.yekan13,
|
||||||
|
errorStyle: AppFonts.yekan13.copyWith(
|
||||||
|
color: AppColor.redNormal,
|
||||||
|
),
|
||||||
|
prefixIconConstraints: BoxConstraints(
|
||||||
|
maxHeight: 40,
|
||||||
|
minHeight: 40,
|
||||||
|
maxWidth: 40,
|
||||||
|
minWidth: 40,
|
||||||
|
),
|
||||||
|
prefixIcon: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
|
||||||
|
child: vecWidget(Assets.vecCallSvg),
|
||||||
|
),
|
||||||
|
suffix:
|
||||||
|
phoneController.value.text.trim().isNotEmpty
|
||||||
|
? clearButton(() {
|
||||||
|
phoneController.value.clear();
|
||||||
|
phoneController.refresh();
|
||||||
|
})
|
||||||
|
: null,
|
||||||
|
counterText: '',
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.numberWithOptions(
|
||||||
|
decimal: false,
|
||||||
|
signed: false,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
maxLength: 11,
|
||||||
|
onChanged: (value) {
|
||||||
|
if (controller.isOnError.value) {
|
||||||
|
controller.isOnError.value = !controller.isOnError.value;
|
||||||
|
data.value.currentState?.reset();
|
||||||
|
data.refresh();
|
||||||
|
phoneController.value.text = value;
|
||||||
|
}
|
||||||
|
phoneController.refresh();
|
||||||
|
},
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) {
|
||||||
|
return '⚠️ شماره موبایل را وارد کنید';
|
||||||
|
} else if (value.length < 11) {
|
||||||
|
return '⚠️ شماره موبایل باید 11 رقم باشد';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
style: AppFonts.yekan13,
|
||||||
|
);
|
||||||
|
}, controller.phoneOtpNumberController),
|
||||||
|
|
||||||
|
SizedBox(height: 26),
|
||||||
|
|
||||||
|
CaptchaWidget(),
|
||||||
|
|
||||||
|
SizedBox(height: 23),
|
||||||
|
RElevated(
|
||||||
|
text: 'ارسال رمز یکبار مصرف',
|
||||||
|
onPressed: () {
|
||||||
|
if (data.value.currentState?.validate() == true) {
|
||||||
|
controller.otpStatus.value = OtpStatus.sent;
|
||||||
|
controller.startTimer();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
width: Get.width,
|
||||||
|
height: 48,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}, controller.formKeyOtp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget confirmCodeForm() {
|
||||||
|
return ObxValue((data) {
|
||||||
|
return Form(
|
||||||
|
key: data.value,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 50),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 26),
|
||||||
|
|
||||||
|
ObxValue((passwordController) {
|
||||||
|
return TextFormField(
|
||||||
|
controller: passwordController.value,
|
||||||
|
obscureText: controller.hidePassword.value,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
gapPadding: 11,
|
||||||
|
),
|
||||||
|
labelText: 'رمز عبور',
|
||||||
|
labelStyle: AppFonts.yekan13,
|
||||||
|
errorStyle: AppFonts.yekan13.copyWith(
|
||||||
|
color: AppColor.redNormal,
|
||||||
|
),
|
||||||
|
|
||||||
|
prefixIconConstraints: BoxConstraints(
|
||||||
|
maxHeight: 34,
|
||||||
|
minHeight: 34,
|
||||||
|
maxWidth: 34,
|
||||||
|
minWidth: 34,
|
||||||
|
),
|
||||||
|
prefixIcon: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
|
||||||
|
child: vecWidget(Assets.vecKeySvg),
|
||||||
|
),
|
||||||
|
suffix:
|
||||||
|
passwordController.value.text.trim().isNotEmpty
|
||||||
|
? GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
controller.hidePassword.value =
|
||||||
|
!controller.hidePassword.value;
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
controller.hidePassword.value
|
||||||
|
? CupertinoIcons.eye
|
||||||
|
: CupertinoIcons.eye_slash,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
counterText: '',
|
||||||
|
),
|
||||||
|
textInputAction: TextInputAction.done,
|
||||||
|
keyboardType: TextInputType.visiblePassword,
|
||||||
|
maxLines: 1,
|
||||||
|
onChanged: (value) {
|
||||||
|
if (controller.isOnError.value) {
|
||||||
|
controller.isOnError.value = !controller.isOnError.value;
|
||||||
|
data.value.currentState?.reset();
|
||||||
|
passwordController.value.text = value;
|
||||||
|
}
|
||||||
|
passwordController.refresh();
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return '⚠️ رمز عبور را وارد کنید'; // "Please enter the password"
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
style: AppFonts.yekan13,
|
||||||
|
);
|
||||||
|
}, controller.passwordController),
|
||||||
|
|
||||||
|
SizedBox(height: 23),
|
||||||
|
|
||||||
|
ObxValue((timer) {
|
||||||
|
if (timer.value == 0) {
|
||||||
|
return TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
controller.otpStatus.value = OtpStatus.reSend;
|
||||||
|
controller.startTimer();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
style: AppFonts.yekan13.copyWith(
|
||||||
|
color: AppColor.blueNormal,
|
||||||
|
),
|
||||||
|
'ارسال مجدد کد یکبار مصرف',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Text(
|
||||||
|
'اعتبار رمز ارسال شده ${controller.timeFormatted}',
|
||||||
|
style: AppFonts.yekan13,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, controller.secondsRemaining),
|
||||||
|
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: ' کد ارسال شده به شماره ',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color: AppColor.darkGreyDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: controller.phoneOtpNumberController.value.text,
|
||||||
|
style: AppFonts.yekan13Bold.copyWith(
|
||||||
|
color: AppColor.darkGreyDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
recognizer:
|
||||||
|
TapGestureRecognizer()
|
||||||
|
..onTap = () {
|
||||||
|
controller.otpStatus.value = OtpStatus.init;
|
||||||
|
},
|
||||||
|
text: ' ویرایش',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color: AppColor.blueNormal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(height: 23),
|
||||||
|
RElevated(
|
||||||
|
text: 'ورود',
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.formKeyOtp.value.currentState?.validate() ==
|
||||||
|
true) {}
|
||||||
|
},
|
||||||
|
width: Get.width,
|
||||||
|
height: 48,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}, controller.formKeySentOtp);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:rasadyar_chicken/data/datasource/local/chicken_local_imp.dart';
|
import 'package:rasadyar_chicken/data/data_source/local/chicken_local_imp.dart';
|
||||||
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
|
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
|
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/response/inventory/inventory_model.dart';
|
import 'package:rasadyar_chicken/data/models/response/inventory/inventory_model.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
|
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
|
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
|
||||||
import 'package:rasadyar_chicken/data/repositories/chicken_repository.dart';
|
import 'package:rasadyar_chicken/data/repositories/chicken/chicken_repository.dart';
|
||||||
import 'package:rasadyar_chicken/data/repositories/chicken_repository_imp.dart';
|
import 'package:rasadyar_chicken/data/repositories/chicken/chicken_repository_imp.dart';
|
||||||
|
|
||||||
import 'package:rasadyar_chicken/presentation/pages/buy/view.dart';
|
import 'package:rasadyar_chicken/presentation/pages/buy/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/home/view.dart';
|
import 'package:rasadyar_chicken/presentation/pages/home/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/profile/view.dart';
|
import 'package:rasadyar_chicken/presentation/pages/profile/view.dart';
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'package:rasadyar_chicken/presentation/pages/auth/logic.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/pages/auth/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/buy/logic.dart';
|
import 'package:rasadyar_chicken/presentation/pages/buy/logic.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/buy/view.dart';
|
import 'package:rasadyar_chicken/presentation/pages/buy/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/buy_in_province/logic.dart';
|
import 'package:rasadyar_chicken/presentation/pages/buy_in_province/logic.dart';
|
||||||
@@ -23,6 +25,7 @@ import 'package:rasadyar_chicken/presentation/pages/sales_out_of_province_sales_
|
|||||||
import 'package:rasadyar_chicken/presentation/pages/segmentation/logic.dart';
|
import 'package:rasadyar_chicken/presentation/pages/segmentation/logic.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
|
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/widget/captcha/logic.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/widget/search/logic.dart';
|
import 'package:rasadyar_chicken/presentation/widget/search/logic.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
@@ -30,6 +33,15 @@ sealed class ChickenPages {
|
|||||||
ChickenPages._();
|
ChickenPages._();
|
||||||
|
|
||||||
static final pages = [
|
static final pages = [
|
||||||
|
GetPage(
|
||||||
|
name: ChickenRoutes.auth,
|
||||||
|
page: () => AuthPage(),
|
||||||
|
binding: BindingsBuilder(() {
|
||||||
|
Get.lazyPut(() => AuthLogic());
|
||||||
|
Get.lazyPut(() => CaptchaWidgetLogic());
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
GetPage(
|
GetPage(
|
||||||
name: ChickenRoutes.init,
|
name: ChickenRoutes.init,
|
||||||
page: () => RootPage(),
|
page: () => RootPage(),
|
||||||
|
|||||||
34
packages/chicken/lib/presentation/widget/captcha/logic.dart
Normal file
34
packages/chicken/lib/presentation/widget/captcha/logic.dart
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
class CaptchaWidgetLogic extends GetxController with StateMixin<String> {
|
||||||
|
TextEditingController textController = TextEditingController();
|
||||||
|
RxnString captchaKey = RxnString();
|
||||||
|
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final Random random = Random();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
|
||||||
|
getCaptcha();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
textController.clear();
|
||||||
|
textController.dispose();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getCaptcha() async {
|
||||||
|
change(null, status: RxStatus.loading());
|
||||||
|
textController.clear();
|
||||||
|
await Future.delayed(Duration(milliseconds: 500));
|
||||||
|
captchaKey.value = (random.nextInt(900_000) + 100_000).toString();
|
||||||
|
change(captchaKey.value, status: RxStatus.success());
|
||||||
|
}
|
||||||
|
}
|
||||||
111
packages/chicken/lib/presentation/widget/captcha/view.dart
Normal file
111
packages/chicken/lib/presentation/widget/captcha/view.dart
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/pages/auth/logic.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
|
||||||
|
import 'logic.dart';
|
||||||
|
|
||||||
|
class CaptchaWidget extends GetView<CaptchaWidgetLogic> {
|
||||||
|
const CaptchaWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: controller.getCaptcha,
|
||||||
|
child: Container(
|
||||||
|
width: 135,
|
||||||
|
height: 50,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColor.whiteNormalHover,
|
||||||
|
border: Border.all(color: Colors.grey.shade300),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: controller.obx(
|
||||||
|
(state) =>Text(
|
||||||
|
state ?? '',
|
||||||
|
style: AppFonts.yekan20Bold.copyWith(color: Colors.black,letterSpacing: 2.5),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
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: RTextField(
|
||||||
|
label: 'کد امنیتی',
|
||||||
|
controller: controller.textController,
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide: BorderSide(color: AppColor.textColor, width: 1),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.numberWithOptions(decimal: false, signed: false),
|
||||||
|
maxLines: 1,
|
||||||
|
maxLength: 6,
|
||||||
|
suffixIcon: (controller.textController.text.trim().isNotEmpty ?? false)
|
||||||
|
? clearButton(() => controller.textController.clear())
|
||||||
|
: null,
|
||||||
|
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return 'کد امنیتی را وارد کنید';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onChanged: (pass) {
|
||||||
|
if (pass.length == 6) {
|
||||||
|
if (controller.formKey.currentState?.validate() ?? false) {
|
||||||
|
Get.find<AuthLogic>().isDisabled.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -4,4 +4,5 @@ export 'fab.dart';
|
|||||||
export 'fab_outlined.dart';
|
export 'fab_outlined.dart';
|
||||||
export 'outline_elevated.dart';
|
export 'outline_elevated.dart';
|
||||||
export 'outline_elevated_icon.dart';
|
export 'outline_elevated_icon.dart';
|
||||||
export 'text_button.dart';
|
export 'text_button.dart';
|
||||||
|
export 'clear_button.dart';
|
||||||
@@ -3,6 +3,7 @@ export 'bottom_navigation/r_bottom_navigation.dart';
|
|||||||
export 'bottom_navigation/wave_bottom_navigation.dart';
|
export 'bottom_navigation/wave_bottom_navigation.dart';
|
||||||
export 'bottom_sheet/base_bottom_sheet.dart';
|
export 'bottom_sheet/base_bottom_sheet.dart';
|
||||||
export 'bottom_sheet/date_picker_bottom_sheet.dart';
|
export 'bottom_sheet/date_picker_bottom_sheet.dart';
|
||||||
|
//buttons
|
||||||
export 'buttons/buttons.dart';
|
export 'buttons/buttons.dart';
|
||||||
export 'card/card_with_icon_with_border.dart';
|
export 'card/card_with_icon_with_border.dart';
|
||||||
export 'chips/r_chips.dart';
|
export 'chips/r_chips.dart';
|
||||||
@@ -12,6 +13,13 @@ export 'draggable_bottom_sheet/draggable_bottom_sheet.dart';
|
|||||||
export 'draggable_bottom_sheet/draggable_bottom_sheet2.dart';
|
export 'draggable_bottom_sheet/draggable_bottom_sheet2.dart';
|
||||||
export 'draggable_bottom_sheet/draggable_bottom_sheet_controller.dart';
|
export 'draggable_bottom_sheet/draggable_bottom_sheet_controller.dart';
|
||||||
export 'empty_widget.dart';
|
export 'empty_widget.dart';
|
||||||
|
//inputs
|
||||||
|
export 'inputs/inputs.dart';
|
||||||
|
//list_item
|
||||||
|
export 'list_item/list_item.dart';
|
||||||
|
export 'list_item/list_item2.dart';
|
||||||
|
export 'list_item/list_item_with_out_number.dart';
|
||||||
|
export 'list_row_item.dart';
|
||||||
export 'list_view/list_view.dart';
|
export 'list_view/list_view.dart';
|
||||||
export 'loading_widget.dart';
|
export 'loading_widget.dart';
|
||||||
export 'overlay_dropdown_widget/view.dart';
|
export 'overlay_dropdown_widget/view.dart';
|
||||||
@@ -21,11 +29,6 @@ export 'tabs/new_tab.dart';
|
|||||||
export 'tabs/r_segment.dart';
|
export 'tabs/r_segment.dart';
|
||||||
export 'tabs/tab.dart';
|
export 'tabs/tab.dart';
|
||||||
export 'vec_widget.dart';
|
export 'vec_widget.dart';
|
||||||
export 'list_row_item.dart';
|
|
||||||
//inputs
|
|
||||||
export 'inputs/inputs.dart';
|
|
||||||
//list_item
|
|
||||||
export 'list_item/list_item.dart';
|
|
||||||
export 'list_item/list_item2.dart';
|
|
||||||
export 'list_item/list_item_with_out_number.dart';
|
|
||||||
|
|
||||||
|
// other
|
||||||
|
export 'logo_widget.dart';
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ import 'package:flutter/gestures.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
import 'package:rasadyar_inspection/presentation/widget/captcha/view.dart';
|
import 'package:rasadyar_inspection/presentation/widget/captcha/view.dart';
|
||||||
import 'package:rasadyar_inspection/presentation/widget/clear_button.dart';
|
|
||||||
import 'package:rasadyar_inspection/presentation/widget/logo_widget.dart';
|
|
||||||
|
|
||||||
import 'logic.dart';
|
import 'logic.dart';
|
||||||
|
|
||||||
class AuthPage extends GetView<AuthLogic> {
|
class AuthPage extends GetView<AuthLogic> {
|
||||||
@@ -45,7 +42,10 @@ class AuthPage extends GetView<AuthLogic> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final screenHeight = MediaQuery.of(context).size.height;
|
final screenHeight = MediaQuery
|
||||||
|
.of(context)
|
||||||
|
.size
|
||||||
|
.height;
|
||||||
final targetTop = (screenHeight - 676) / 2;
|
final targetTop = (screenHeight - 676) / 2;
|
||||||
|
|
||||||
return AnimatedPositioned(
|
return AnimatedPositioned(
|
||||||
@@ -129,11 +129,13 @@ class AuthPage extends GetView<AuthLogic> {
|
|||||||
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
|
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
|
||||||
child: Assets.vec.callSvg.svg(width: 12, height: 12),
|
child: Assets.vec.callSvg.svg(width: 12, height: 12),
|
||||||
),
|
),
|
||||||
suffixIcon: controller.usernameController.value.text.trim().isNotEmpty
|
suffixIcon: controller.usernameController.value.text
|
||||||
|
.trim()
|
||||||
|
.isNotEmpty
|
||||||
? clearButton(() {
|
? clearButton(() {
|
||||||
controller.usernameController.value.clear();
|
controller.usernameController.value.clear();
|
||||||
controller.usernameController.refresh();
|
controller.usernameController.refresh();
|
||||||
})
|
})
|
||||||
: null,
|
: null,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
@@ -155,41 +157,42 @@ class AuthPage extends GetView<AuthLogic> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 26),
|
const SizedBox(height: 26),
|
||||||
ObxValue(
|
ObxValue(
|
||||||
(passwordController) => RTextField(
|
(passwordController) =>
|
||||||
label: 'رمز عبور',
|
RTextField(
|
||||||
filled: false,
|
label: 'رمز عبور',
|
||||||
obscure: true,
|
filled: false,
|
||||||
focusedBorder: OutlineInputBorder(
|
obscure: true,
|
||||||
borderRadius: BorderRadius.circular(8),
|
focusedBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: AppColor.textColor, width: 1),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
borderSide: BorderSide(color: AppColor.textColor, width: 1),
|
||||||
controller: passwordController.value,
|
),
|
||||||
autofillHints: [AutofillHints.password],
|
controller: passwordController.value,
|
||||||
variant: RTextFieldVariant.password,
|
autofillHints: [AutofillHints.password],
|
||||||
initText: passwordController.value.text,
|
variant: RTextFieldVariant.password,
|
||||||
onChanged: (value) {
|
initText: passwordController.value.text,
|
||||||
passwordController.refresh();
|
onChanged: (value) {
|
||||||
},
|
passwordController.refresh();
|
||||||
validator: (value) {
|
},
|
||||||
if (value == null || value.isEmpty) {
|
validator: (value) {
|
||||||
return '⚠️ رمز عبور را وارد کنید';
|
if (value == null || value.isEmpty) {
|
||||||
}
|
return '⚠️ رمز عبور را وارد کنید';
|
||||||
return null;
|
}
|
||||||
},
|
return null;
|
||||||
style: AppFonts.yekan13,
|
},
|
||||||
errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
|
style: AppFonts.yekan13,
|
||||||
labelStyle: AppFonts.yekan13,
|
errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
|
||||||
prefixIcon: Padding(
|
labelStyle: AppFonts.yekan13,
|
||||||
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
|
prefixIcon: Padding(
|
||||||
child: Assets.vec.keySvg.svg(width: 12, height: 12),
|
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
|
||||||
),
|
child: Assets.vec.keySvg.svg(width: 12, height: 12),
|
||||||
boxConstraints: const BoxConstraints(
|
),
|
||||||
maxHeight: 34,
|
boxConstraints: const BoxConstraints(
|
||||||
minHeight: 34,
|
maxHeight: 34,
|
||||||
maxWidth: 34,
|
minHeight: 34,
|
||||||
minWidth: 34,
|
maxWidth: 34,
|
||||||
),
|
minWidth: 34,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
controller.passwordController,
|
controller.passwordController,
|
||||||
),
|
),
|
||||||
SizedBox(height: 26),
|
SizedBox(height: 26),
|
||||||
@@ -203,8 +206,8 @@ class AuthPage extends GetView<AuthLogic> {
|
|||||||
onPressed: controller.isDisabled.value
|
onPressed: controller.isDisabled.value
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
await controller.submitLoginForm();
|
await controller.submitLoginForm();
|
||||||
},
|
},
|
||||||
width: Get.width,
|
width: Get.width,
|
||||||
height: 48,
|
height: 48,
|
||||||
);
|
);
|
||||||
@@ -305,7 +308,7 @@ class AuthPage extends GetView<AuthLogic> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Widget sendCodeForm() {
|
Widget sendCodeForm() {
|
||||||
return ObxValue((data) {
|
return ObxValue((data) {
|
||||||
return Form(
|
return Form(
|
||||||
|
|||||||
@@ -13,6 +13,15 @@ sealed class InspectionPages {
|
|||||||
InspectionPages._();
|
InspectionPages._();
|
||||||
|
|
||||||
static final pages = [
|
static final pages = [
|
||||||
|
|
||||||
|
GetPage(
|
||||||
|
name: InspectionRoutes.auth,
|
||||||
|
page: () => AuthPage(),
|
||||||
|
binding: BindingsBuilder(() {
|
||||||
|
Get.lazyPut(() => AuthLogic());
|
||||||
|
Get.lazyPut(() => CaptchaWidgetLogic());
|
||||||
|
}),
|
||||||
|
),
|
||||||
GetPage(
|
GetPage(
|
||||||
name: InspectionRoutes.init,
|
name: InspectionRoutes.init,
|
||||||
page: () => RootPage(),
|
page: () => RootPage(),
|
||||||
@@ -64,13 +73,6 @@ sealed class InspectionPages {
|
|||||||
page: () => AddMobileInspectorPage(),
|
page: () => AddMobileInspectorPage(),
|
||||||
binding: BindingsBuilder.put(() => AddMobileInspectorLogic()),
|
binding: BindingsBuilder.put(() => AddMobileInspectorLogic()),
|
||||||
),
|
),
|
||||||
GetPage(
|
|
||||||
name: InspectionRoutes.auth,
|
|
||||||
page: () => AuthPage(),
|
|
||||||
binding: BindingsBuilder(() {
|
|
||||||
Get.lazyPut(() => AuthLogic());
|
|
||||||
Get.lazyPut(() => CaptchaWidgetLogic());
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
import 'package:rasadyar_inspection/presentation/pages/auth/logic.dart';
|
import 'package:rasadyar_inspection/presentation/pages/auth/logic.dart';
|
||||||
import 'package:rasadyar_inspection/presentation/widget/clear_button.dart';
|
|
||||||
|
|
||||||
import 'logic.dart';
|
import 'logic.dart';
|
||||||
|
|
||||||
@@ -29,7 +29,8 @@ class CaptchaWidget extends GetView<CaptchaWidgetLogic> {
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: controller.obx(
|
child: controller.obx(
|
||||||
(state) => Image.memory(base64Decode(state?.captchaImage ?? ''), fit: BoxFit.cover),
|
(state) =>
|
||||||
|
Image.memory(base64Decode(state?.captchaImage ?? ''), fit: BoxFit.cover),
|
||||||
onLoading: const Center(
|
onLoading: const Center(
|
||||||
child: CupertinoActivityIndicator(color: AppColor.blueNormal),
|
child: CupertinoActivityIndicator(color: AppColor.blueNormal),
|
||||||
),
|
),
|
||||||
@@ -57,7 +58,9 @@ class CaptchaWidget extends GetView<CaptchaWidgetLogic> {
|
|||||||
keyboardType: TextInputType.numberWithOptions(decimal: false, signed: false),
|
keyboardType: TextInputType.numberWithOptions(decimal: false, signed: false),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
maxLength: 6,
|
maxLength: 6,
|
||||||
suffixIcon: (controller.textController.text.trim().isNotEmpty ?? false)
|
suffixIcon: (controller.textController.text
|
||||||
|
.trim()
|
||||||
|
.isNotEmpty ?? false)
|
||||||
? clearButton(() => controller.textController.clear())
|
? clearButton(() => controller.textController.clear())
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
@@ -70,7 +73,10 @@ class CaptchaWidget extends GetView<CaptchaWidgetLogic> {
|
|||||||
onChanged: (pass) {
|
onChanged: (pass) {
|
||||||
if (pass.length == 6) {
|
if (pass.length == 6) {
|
||||||
if (controller.formKey.currentState?.validate() ?? false) {
|
if (controller.formKey.currentState?.validate() ?? false) {
|
||||||
Get.find<AuthLogic>().isDisabled.value = false;
|
Get
|
||||||
|
.find<AuthLogic>()
|
||||||
|
.isDisabled
|
||||||
|
.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user