chore : delete auth package because each project has different auth , must be separated auth logic
This commit is contained in:
168
packages/inspection/lib/presentation/pages/auth/logic.dart
Normal file
168
packages/inspection/lib/presentation/pages/auth/logic.dart
Normal file
@@ -0,0 +1,168 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
import 'package:rasadyar_core/data/model/request/login_request/login_request_model.dart';
|
||||
import 'package:rasadyar_core/data/model/response/user_info/user_info_model.dart';
|
||||
import 'package:rasadyar_core/data/model/response/user_profile_model/user_profile_model.dart';
|
||||
import 'package:rasadyar_inspection/data/repositories/auth_repository_imp.dart';
|
||||
import 'package:rasadyar_inspection/presentation/widget/captcha/logic.dart';
|
||||
|
||||
enum AuthType { useAndPass, otp }
|
||||
|
||||
enum AuthStatus { init }
|
||||
|
||||
enum OtpStatus { init, sent, verified, reSend }
|
||||
|
||||
class AuthLogic extends GetxController {
|
||||
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
|
||||
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 = diAuth.get<AuthRepositoryImpl>();
|
||||
|
||||
final Module _module = Get.arguments;
|
||||
|
||||
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')}';
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
iLog('module selected : ${_module.toString()}');
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_timer?.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
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;
|
||||
iLog('module222 : ${_module.toString()}');
|
||||
final loginRequestModel = _buildLoginRequest();
|
||||
isLoading.value = true;
|
||||
await safeCall<AuthResponseModel?>(
|
||||
call: () => authRepository.login(authRequest: loginRequestModel.toJson()),
|
||||
onSuccess: (result) async {
|
||||
await tokenStorageService.saveModule(_module);
|
||||
await tokenStorageService.saveRefreshToken(result?.refresh ?? '');
|
||||
await tokenStorageService.saveAccessToken(result?.access ?? '');
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
if (error is DioException) {
|
||||
diAuth.get<DioErrorHandler>().handle(error);
|
||||
}
|
||||
captchaController.getCaptcha();
|
||||
},
|
||||
);
|
||||
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": 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) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
524
packages/inspection/lib/presentation/pages/auth/view.dart
Normal file
524
packages/inspection/lib/presentation/pages/auth/view.dart
Normal file
@@ -0,0 +1,524 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_core/core.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';
|
||||
|
||||
class AuthPage extends GetView<AuthLogic> {
|
||||
const AuthPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 80),
|
||||
LogoWidget(),
|
||||
ObxValue((types) {
|
||||
switch (types.value) {
|
||||
case AuthType.otp:
|
||||
//return otpForm();
|
||||
case AuthType.useAndPass:
|
||||
return useAndPassFrom();
|
||||
}
|
||||
}, controller.authType),
|
||||
|
||||
SizedBox(height: 20),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
/* SizedBox(height: 18),
|
||||
|
||||
ObxValue((types) {
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
if (controller.authType.value == AuthType.otp) {
|
||||
controller.authType.value = AuthType.useAndPass;
|
||||
if (controller.otpStatus.value !=
|
||||
OtpStatus.init) {
|
||||
controller.otpStatus.value = OtpStatus.init;
|
||||
}
|
||||
} else {
|
||||
controller.authType.value = AuthType.otp;
|
||||
}
|
||||
},
|
||||
text:
|
||||
controller.authType.value == AuthType.otp
|
||||
? 'ورود با رمز ثابت'
|
||||
: 'ورود با رمز یکبار مصرف',
|
||||
|
||||
style: AppFonts.yekan14.copyWith(
|
||||
color: AppColor.blueNormal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}, controller.authType),*/
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget useAndPassFrom() {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 50),
|
||||
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],
|
||||
onChanged: (value) async {
|
||||
controller.usernameController.value.text = value;
|
||||
controller.usernameController.refresh();
|
||||
},
|
||||
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,
|
||||
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(
|
||||
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,4 +1,6 @@
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
import 'package:rasadyar_inspection/presentation/pages/auth/logic.dart';
|
||||
import 'package:rasadyar_inspection/presentation/pages/auth/view.dart';
|
||||
import 'package:rasadyar_inspection/presentation/pages/filter/logic.dart';
|
||||
import 'package:rasadyar_inspection/presentation/pages/pages.dart';
|
||||
import 'package:rasadyar_inspection/presentation/pages/users/logic.dart';
|
||||
@@ -12,10 +14,10 @@ sealed class InspectionPages {
|
||||
GetPage(
|
||||
name: InspectionRoutes.init,
|
||||
page: () => RootPage(),
|
||||
|
||||
middlewares:[ AuthMiddleware()],
|
||||
binding: BindingsBuilder(() {
|
||||
Get.lazyPut(() =>RootLogic());
|
||||
Get.lazyPut(() =>InspectorFilterLogic());
|
||||
Get.lazyPut(() => RootLogic());
|
||||
Get.lazyPut(() => InspectorFilterLogic());
|
||||
Get.lazyPut(() => InspectionMapLogic());
|
||||
Get.lazyPut(() => BaseLogic());
|
||||
Get.lazyPut(() => UsersLogic());
|
||||
@@ -59,5 +61,10 @@ sealed class InspectionPages {
|
||||
page: () => AddMobileInspectorPage(),
|
||||
binding: BindingsBuilder.put(() => AddMobileInspectorLogic()),
|
||||
),
|
||||
GetPage(
|
||||
name: InspectionRoutes.auth,
|
||||
page: () => AuthPage(),
|
||||
binding: BindingsBuilder.put(() => AuthLogic()),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ sealed class InspectionRoutes {
|
||||
InspectionRoutes._();
|
||||
|
||||
static const init = '/supervision';
|
||||
static const inspectionAction = '$init/action';
|
||||
static const auth = '/AuthSupervision';
|
||||
static const inspectionUserProfile = '$init/userSettings';
|
||||
static const inspectionLocationDetails = '$init/locationDetails';
|
||||
static const inspectionAddSupervision = '$inspectionLocationDetails/addSupervision';
|
||||
static const inspectionAddMobileInspector = '$inspectionLocationDetails/addMobileInspector';
|
||||
static const inspectionRegistrationOfViolation = '$inspectionAddSupervision/RegistrationOfViolation';
|
||||
static const inspectionDisplayInformation = '$inspectionRegistrationOfViolation/DisplayInformation';
|
||||
static const inspectionRegistrationOfViolation =
|
||||
'$inspectionAddSupervision/RegistrationOfViolation';
|
||||
static const inspectionDisplayInformation =
|
||||
'$inspectionRegistrationOfViolation/DisplayInformation';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
import 'package:rasadyar_core/data/model/response/captcha/captcha_response_model.dart';
|
||||
import 'package:rasadyar_inspection/data/repositories/auth_repository_imp.dart';
|
||||
|
||||
class CaptchaWidgetLogic extends GetxController with StateMixin<CaptchaResponseModel> {
|
||||
TextEditingController textController = TextEditingController();
|
||||
RxnString captchaKey = RxnString();
|
||||
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
//AuthRepositoryImpl authRepository = .get<AuthRepositoryImpl>();
|
||||
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: 800));
|
||||
captchaKey.value = (random.nextInt(900000) + 100000).toString();
|
||||
change(value, status: RxStatus.success());
|
||||
}
|
||||
}
|
||||
109
packages/inspection/lib/presentation/widget/captcha/view.dart
Normal file
109
packages/inspection/lib/presentation/widget/captcha/view.dart
Normal file
@@ -0,0 +1,109 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
import 'package:rasadyar_inspection/presentation/pages/auth/logic.dart';
|
||||
import 'package:rasadyar_inspection/presentation/widget/clear_button.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,
|
||||
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,
|
||||
),
|
||||
),
|
||||
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,
|
||||
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 'کد امنیتی را وارد کنید';
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
},
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
Widget clearButton(VoidCallback onTap) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Icon(CupertinoIcons.multiply_circle, size: 20),
|
||||
);
|
||||
}
|
||||
23
packages/inspection/lib/presentation/widget/logo_widget.dart
Normal file
23
packages/inspection/lib/presentation/widget/logo_widget.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class LogoWidget extends StatelessWidget {
|
||||
const LogoWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(),
|
||||
Assets.images.innerSplash.image(
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
Text(
|
||||
'سامانه رصدیار',
|
||||
style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyNormal),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user