Merge branch 'refs/heads/feature/chicken' into feature/inspectionV1.0.2

# Conflicts:
#	packages/auth/lib/presentation/pages/auth/view.dart
#	packages/auth/pubspec.yaml
#	packages/core/lib/presentation/widget/app_bar/r_app_bar.dart
#	packages/core/lib/presentation/widget/inputs/r_input.dart
This commit is contained in:
2025-07-24 12:07:43 +03:30
365 changed files with 52723 additions and 1865 deletions

View File

@@ -4,7 +4,8 @@ import 'package:flutter/material.dart';
import 'package:rasadyar_auth/auth.dart';
import 'package:rasadyar_auth/data/common/dio_error_handler.dart';
import 'package:rasadyar_auth/data/models/request/login_request/login_request_model.dart';
import 'package:rasadyar_auth/data/models/response/auth/auth_response_model.dart';
import 'package:rasadyar_auth/data/models/response/user_info/user_info_model.dart';
import 'package:rasadyar_auth/data/models/response/user_profile_model/user_profile_model.dart';
import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart';
import 'package:rasadyar_auth/data/services/token_storage_service.dart';
import 'package:rasadyar_auth/data/utils/safe_call.dart';
@@ -26,14 +27,14 @@ class AuthLogic extends GetxController {
Rx<GlobalKey<FormState>> formKeySentOtp = GlobalKey<FormState>().obs;
Rx<TextEditingController> usernameController = TextEditingController().obs;
Rx<TextEditingController> passwordController = TextEditingController().obs;
Rx<TextEditingController> phoneOtpNumberController =
TextEditingController().obs;
Rx<TextEditingController> phoneOtpNumberController = TextEditingController().obs;
Rx<TextEditingController> otpCodeController = TextEditingController().obs;
var captchaController = Get.find<CaptchaWidgetLogic>();
RxnString phoneNumber = RxnString(null);
RxBool isLoading = false.obs;
RxBool isDisabled = true.obs;
TokenStorageService tokenStorageService = Get.find<TokenStorageService>();
Rx<AuthType> authType = AuthType.useAndPass.obs;
@@ -70,15 +71,11 @@ class AuthLogic extends GetxController {
return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
}
@override
void onInit() {
super.onInit();
}
@override
void onReady() {
super.onReady();
iLog('module111 : ${_module.toString()}');
iLog('module selected : ${_module.toString()}');
}
@override
@@ -88,8 +85,7 @@ class AuthLogic extends GetxController {
}
bool _isFormValid() {
final isCaptchaValid =
captchaController.formKey.currentState?.validate() ?? false;
final isCaptchaValid = captchaController.formKey.currentState?.validate() ?? false;
final isFormValid = formKey.currentState?.validate() ?? false;
return isCaptchaValid && isFormValid;
}
@@ -108,7 +104,7 @@ class AuthLogic extends GetxController {
);
}
Future<void> submitLoginForm() async {
/*Future<void> submitLoginForm() async {
if (!_isFormValid()) return;
iLog('module222 : ${_module.toString()}');
final loginRequestModel = _buildLoginRequest();
@@ -128,5 +124,52 @@ class AuthLogic extends GetxController {
},
);
isLoading.value = false;
}*/
Future<void> submitLoginForm2() async {
if (!_isFormValid()) return;
AuthRepositoryImpl authTmp = diAuth.get<AuthRepositoryImpl>(instanceName: 'newUrl');
isLoading.value = true;
await safeCall<UserProfileModel?>(
call: () => authTmp.login(
authRequest: {
"username": phoneNumberController.value.text,
"password": passwordController.value.text,
},
),
onSuccess: (result) async {
await tokenStorageService.saveModule(_module);
await tokenStorageService.saveAccessToken(result?.accessToken ?? '');
await tokenStorageService.saveRefreshToken(result?.accessToken ?? '');
},
onError: (error, stackTrace) {
if (error is DioException) {
diAuth.get<DioErrorHandler>().handle(error);
}
captchaController.getCaptcha();
},
);
isLoading.value = false;
}
Future<void> getUserInfo(String value) async {
isLoading.value = true;
await safeCall<UserInfoModel?>(
call: () async => await authRepository.getUserInfo(value),
onSuccess: (result) async {
if (result != null) {
await newSetupAuthDI(result.backend ?? '');
await tokenStorageService.saveApiKey(result.apiKey ?? '');
await tokenStorageService.saveBaseUrl(result.backend ?? '');
}
},
onError: (error, stackTrace) {
if (error is DioException) {
diAuth.get<DioErrorHandler>().handle(error);
}
captchaController.getCaptcha();
},
);
isLoading.value = false;
}
}

View File

@@ -27,28 +27,31 @@ class AuthPage extends GetView<AuthLogic> {
}
}, controller.authType),
SizedBox(height: 50),
SizedBox(height: 20),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'مطالعه بیانیه ',
style: AppFonts.yekan14.copyWith(
color: AppColor.darkGreyDark,
),
style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyDark),
),
TextSpan(
recognizer: TapGestureRecognizer()
..onTap = () {},
..onTap = () {
Get.bottomSheet(
privacyPolicyWidget(),
isScrollControlled: true,
enableDrag: true,
ignoreSafeArea: false,
);
},
text: 'حریم خصوصی',
style: AppFonts.yekan14.copyWith(
color: AppColor.blueNormal,
),
style: AppFonts.yekan16.copyWith(color: AppColor.blueNormal),
),
],
),
),
SizedBox(height: 18),
/* SizedBox(height: 18),
ObxValue((types) {
return RichText(
@@ -80,7 +83,7 @@ class AuthPage extends GetView<AuthLogic> {
],
),
);
}, controller.authType),
}, controller.authType),*/
],
),
),
@@ -92,120 +95,201 @@ class AuthPage extends GetView<AuthLogic> {
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 50),
child: Form(
key: controller.formKey,
child: Column(
children: [
ObxValue(
(phoneController) =>
RTextField(
label: 'نام کاربری',
maxLength: 11,
maxLines: 1,
controller: phoneController.value,
keyboardType: TextInputType.text,
initText: phoneController.value.text,
onChanged: (value) {
phoneController.value.text = value;
phoneController.refresh();
},
prefixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
child: Assets.vec.callSvg.svg(
width: 12,
height: 12,
),
),
suffixIcon:
phoneController.value.text
.trim()
.isNotEmpty
? clearButton(() {
phoneController.value.clear();
phoneController.refresh();
})
: null,
validator: (value) {
if (value == null || value.isEmpty) {
return '⚠️ شماره موبایل را وارد کنید';
}
/*else if (value.length < 11) {
return '⚠️ شماره موبایل باید 11 رقم باشد';
}*/
return null;
},
style: AppFonts.yekan13,
errorStyle: AppFonts.yekan13.copyWith(
color: AppColor.redNormal,
),
labelStyle: AppFonts.yekan13,
boxConstraints: const BoxConstraints(
maxHeight: 40,
minHeight: 40,
maxWidth: 40,
minWidth: 40,
),
),
controller.usernameController,
),
const SizedBox(height: 26),
ObxValue(
(passwordController) =>
RTextField(
label: 'رمز عبور',
filled: false,
controller: passwordController.value,
variant: RTextFieldVariant.password,
initText: passwordController.value.text,
onChanged: (value) {
passwordController.refresh();
},
validator: (value) {
if (value == null || value.isEmpty) {
return '⚠️ رمز عبور را وارد کنید';
}
return null;
},
style: AppFonts.yekan13,
errorStyle: AppFonts.yekan13.copyWith(
color: AppColor.redNormal,
),
labelStyle: AppFonts.yekan13,
prefixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
child: Assets.vec.keySvg.svg(
width: 12,
height: 12,
),
),
boxConstraints: const BoxConstraints(
maxHeight: 34,
minHeight: 34,
maxWidth: 34,
minWidth: 34,
),
),
controller.passwordController,
),
SizedBox(height: 26),
CaptchaWidget(),
SizedBox(height: 23),
ObxValue((data) {
return RElevated(
text: 'ورود',
isLoading: data.value,
onPressed: () async {
await controller.submitLoginForm();
child: AutofillGroup(
child: Column(
children: [
RTextField(
label: 'نام کاربری',
maxLength: 11,
maxLines: 1,
controller: controller.phoneNumberController.value,
keyboardType: TextInputType.number,
initText: controller.phoneNumberController.value.text,
autofillHints: [AutofillHints.username],
onChanged: (value) async {
controller.phoneNumberController.value.text = value;
controller.phoneNumberController.refresh();
if (value.length == 11) {
await controller.getUserInfo(value);
}
},
width: Get.width,
height: 48,
);
}, controller.isLoading),
],
prefixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
child: Assets.vec.callSvg.svg(width: 12, height: 12),
),
suffixIcon: controller.phoneNumberController.value.text.trim().isNotEmpty
? clearButton(() {
controller.phoneNumberController.value.clear();
controller.phoneNumberController.refresh();
})
: null,
validator: (value) {
if (value == null || value.isEmpty) {
return '⚠️ شماره موبایل را وارد کنید';
} else if (value.length < 11) {
return '⚠️ شماره موبایل باید 11 رقم باشد';
}
return null;
},
style: AppFonts.yekan13,
errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
labelStyle: AppFonts.yekan13,
boxConstraints: const BoxConstraints(
maxHeight: 40,
minHeight: 40,
maxWidth: 40,
minWidth: 40,
),
),
const SizedBox(height: 26),
ObxValue(
(passwordController) => RTextField(
label: 'رمز عبور',
filled: false,
obscure: true,
controller: passwordController.value,
autofillHints: [AutofillHints.password],
variant: RTextFieldVariant.password,
initText: passwordController.value.text,
onChanged: (value) {
passwordController.refresh();
},
validator: (value) {
if (value == null || value.isEmpty) {
return '⚠️ رمز عبور را وارد کنید';
}
return null;
},
style: AppFonts.yekan13,
errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
labelStyle: AppFonts.yekan13,
prefixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
child: Assets.vec.keySvg.svg(width: 12, height: 12),
),
boxConstraints: const BoxConstraints(
maxHeight: 34,
minHeight: 34,
maxWidth: 34,
minWidth: 34,
),
),
controller.passwordController,
),
SizedBox(height: 26),
CaptchaWidget(),
SizedBox(height: 23),
Obx(() {
return RElevated(
text: 'ورود',
isLoading: controller.isLoading.value,
onPressed: controller.isDisabled.value
? null
: () async {
await controller.submitLoginForm2();
},
width: Get.width,
height: 48,
);
}),
],
),
),
),
);
}
/*
Widget privacyPolicyWidget() {
return BaseBottomSheet(
child: Column(
spacing: 5,
children: [
Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 3,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'بيانيه حريم خصوصی',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
Text(
'اطلاعات مربوط به هر شخص، حریم خصوصی وی محسوب می‌شود. حفاظت و حراست از اطلاعات شخصی در سامانه رصد یار، نه تنها موجب حفظ امنیت کاربران می‌شود، بلکه باعث اعتماد بیشتر و مشارکت آنها در فعالیت‌های جاری می‌گردد. هدف از این بیانیه، آگاه ساختن شما درباره ی نوع و نحوه ی استفاده از اطلاعاتی است که در هنگام استفاده از سامانه رصد یار ، از جانب شما دریافت می‌گردد. شرکت هوشمند سازان خود را ملزم به رعایت حریم خصوصی همه شهروندان و کاربران سامانه دانسته و آن دسته از اطلاعات کاربران را که فقط به منظور ارائه خدمات کفایت می‌کند، دریافت کرده و از انتشار آن یا در اختیار قرار دادن آن به دیگران خودداری مینماید.',
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
),
],
),
),
Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'چگونگی جمع آوری و استفاده از اطلاعات کاربران',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
Text(
'''الف: اطلاعاتی که شما خود در اختيار این سامانه قرار می‌دهيد، شامل موارد زيرهستند:
اقلام اطلاعاتی شامل شماره تلفن همراه، تاریخ تولد، کد پستی و کد ملی کاربران را دریافت مینماییم که از این اقلام، صرفا جهت احراز هویت کاربران استفاده خواهد شد.
ب: برخی اطلاعات ديگر که به صورت خودکار از شما دريافت میشود شامل موارد زير می‌باشد:
⦁ دستگاهی که از طریق آن سامانه رصد یار را مشاهده می‌نمایید( تلفن همراه، تبلت، رایانه).
⦁ نام و نسخه سیستم عامل و browser کامپیوتر شما.
⦁ اطلاعات صفحات بازدید شده.
⦁ تعداد بازدیدهای روزانه در درگاه.
⦁ هدف ما از دریافت این اطلاعات استفاده از آنها در تحلیل عملکرد کاربران درگاه می باشد تا بتوانیم در خدمت رسانی بهتر عمل کنیم.
''',
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
),
],
),
),
Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'امنیت اطلاعات',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
Text(
'متعهدیم که امنیت اطلاعات شما را تضمین نماییم و برای جلوگیری از هر نوع دسترسی غیرمجاز و افشای اطلاعات شما از همه شیوه‌‌های لازم استفاده می‌کنیم تا امنیت اطلاعاتی را که به صورت آنلاین گردآوری می‌کنیم، حفظ شود. لازم به ذکر است در سامانه ما، ممکن است به سایت های دیگری لینک شوید، وقتی که شما از طریق این لینک‌ها از سامانه ما خارج می‌شوید، توجه داشته باشید که ما بر دیگر سایت ها کنترل نداریم و سازمان تعهدی بر حفظ حریم شخصی آنان در سایت مقصد نخواهد داشت و مراجعه کنندگان میبایست به بیانیه حریم شخصی آن سایت ها مراجعه نمایند.',
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
),
],
),
),
],
),
);
}
/*
Widget sendCodeForm() {
return ObxValue((data) {
return Form(

View File

@@ -7,6 +7,7 @@ class ModulesLogic extends GetxController {
List<ModuleModel> moduleList=[
ModuleModel(title: 'بازرسی', icon: Assets.icons.inspection.path, module: Module.inspection),
ModuleModel(title: 'دام', icon: Assets.icons.liveStock.path, module: Module.liveStocks),
ModuleModel(title: 'مرغ', icon: Assets.icons.liveStock.path, module: Module.chicken),
];