Merge branch with resolved conflicts - restructured features and added new modules

This commit is contained in:
2025-12-17 10:26:39 +03:30
484 changed files with 55236 additions and 4255 deletions

View File

@@ -1,4 +1,6 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
- hive_ce: true
- hive_ce: true
- provider: true
- shared_preferences: true

View File

@@ -1,3 +1,12 @@
import 'package:rasadyar_chicken/features/city_jahad/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/poultry_science/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/province_inspector/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/province_operator/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/province_supervisor/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/steward/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/super_admin/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/jahad/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/vet_farm/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
String getFaUserRole(String? role) {
@@ -88,7 +97,7 @@ Map<String, String?> getFaUserRoleWithOnTap(String? role) {
case "Poultry":
return {"مرغدار": null};
case "ProvinceOperator":
return {"مدیر اجرایی": null};
return {"مدیر اجرایی": ProvinceOperatorRoutes.initProvinceOperator};
case "ProvinceFinancial":
return {"مالی اتحادیه": null};
case "KillHouse":
@@ -96,17 +105,17 @@ Map<String, String?> getFaUserRoleWithOnTap(String? role) {
case "KillHouseVet":
return {"دامپزشک کشتارگاه": null};
case "VetFarm":
return {"دامپزشک فارم": null};
return {"دامپزشک فارم": VetFarmRoutes.initVetFarm};
case "Driver":
return {"راننده": null};
case "ProvinceInspector":
return {"بازرس اتحادیه": null};
return {"بازرس اتحادیه": ProvinceInspectorRoutes.initProvinceInspector};
case "VetSupervisor":
return {"دامپزشک کل": null};
case "Jahad":
return {"جهاد کشاورزی استان": null};
return {"جهاد کشاورزی استان": JahadRoutes.initJahad};
case "CityJahad":
return {"جهاد کشاورزی شهرستان": null};
return {"جهاد کشاورزی شهرستان": CityJahadRoutes.initCityJahad};
case "ProvincialGovernment":
return {"استانداری": null};
case "Guilds":
@@ -122,7 +131,7 @@ Map<String, String?> getFaUserRoleWithOnTap(String? role) {
case "Observatory":
return {"رصدخانه": null};
case "ProvinceSupervisor":
return {"ناظر استان": null};
return {"ناظر استان": ProvinceSupervisorRoutes.initProvinceSupervisor};
case "GuildRoom":
return {"اتاق اصناف": null};
case "PosCompany":
@@ -130,7 +139,7 @@ Map<String, String?> getFaUserRoleWithOnTap(String? role) {
case "LiveStockSupport":
return {"پشتیبانی امور دام": null};
case "SuperAdmin":
return {"ادمین کل": null};
return {"ادمین کل": SuperAdminRoutes.initSuperAdmin};
case "ChainCompany":
return {"شرکت زنجیره": null};
case "AdminX":
@@ -150,9 +159,9 @@ Map<String, String?> getFaUserRoleWithOnTap(String? role) {
case "LiveStockProvinceJahad":
return {"جهاد استان": null};
case "Steward":
return {"مباشر": ChickenRoutes.initSteward};
return {"مباشر": StewardRoutes.initSteward};
case "PoultryScience":
return {"کارشناس طیور": ChickenRoutes.initPoultryScience};
return {"کارشناس طیور": PoultryScienceRoutes.initPoultryScience};
default:
return {"نامشخص": null};
}

View File

@@ -1,208 +0,0 @@
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/create_steward_free_bar/create_steward_free_bar.dart';
import 'package:rasadyar_chicken/data/models/request/steward_free_sale_bar/steward_free_sale_bar_request.dart';
import 'package:rasadyar_chicken/data/models/request/submit_steward_allocation/submit_steward_allocation.dart';
import 'package:rasadyar_chicken/data/models/response/allocated_made/allocated_made.dart';
import 'package:rasadyar_chicken/data/models/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/data/models/response/dashboard_kill_house_free_bar/dashboard_kill_house_free_bar.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/data/models/response/imported_loads_model/imported_loads_model.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar/steward_free_bar.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar_dashboard/steward_free_bar_dashboard.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_sale_bar/steward_free_sale_bar.dart';
import 'package:rasadyar_chicken/data/models/response/steward_remain_weight/steward_remain_weight.dart';
import 'package:rasadyar_chicken/data/models/response/steward_sales_info_dashboard/steward_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/data/models/response/user_profile/user_profile.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart'
hide ProductModel;
import 'package:rasadyar_core/core.dart';
abstract class ChickenRemoteDatasource {
Future<List<ProductModel>?> getRolesProducts({
required String token,
CancelToken? cancelToken,
Map<String, dynamic>? queryParameters,
});
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
});
Future<BarInformation?> getGeneralBarInformation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<WaitingArrivalModel>?> getWaitingArrivals({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> setSateForArrivals({
required String token,
required Map<String, dynamic> request,
});
Future<PaginationModel<ImportedLoadsModel>?> getImportedLoadsModel({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<AllocatedMadeModel>?> getAllocatedMade({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> confirmAllocation({
required String token,
required Map<String, dynamic> allocation,
});
Future<void> denyAllocation({
required String token,
required String allocationToken,
});
Future<void> confirmAllAllocation({
required String token,
required List<String> allocationTokens,
});
Future<List<GuildModel>?> getGuilds({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<GuildProfile?> getProfile({required String token});
Future<void> postSubmitStewardAllocation({
required String token,
required SubmitStewardAllocation request,
});
Future<void> deleteStewardAllocation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> updateStewardAllocation({
required String token,
required ConformAllocation request,
});
Future<StewardFreeBarDashboard?> getStewardDashboard({
required String token,
required String stratDate,
required String endDate,
});
Future<DashboardKillHouseFreeBar?> getDashboardKillHouseFreeBar({
required String token,
required String stratDate,
required String endDate,
});
Future<PaginationModel<StewardFreeBar>?>
getStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createStewardPurchasesOutSideOfTheProvince({
required String token,
required CreateStewardFreeBar body,
});
Future<void> deleteStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<CreateStewardFreeBar?> editStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<OutProvinceCarcassesBuyer>?>
getOutProvinceCarcassesBuyer({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createOutProvinceCarcassesBuyer({
required String token,
required OutProvinceCarcassesBuyer body,
});
Future<List<IranProvinceCityModel>?> getProvince({CancelToken? cancelToken});
Future<List<IranProvinceCityModel>?> getCity({required String provinceName});
Future<PaginationModel<StewardFreeSaleBar>?> getStewardFreeSaleBar({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createOutProvinceStewardFreeBar({
required String token,
required StewardFreeSaleBarRequest body,
});
Future<void> updateOutProvinceStewardFreeBar({
required String token,
required StewardFreeSaleBarRequest body,
});
Future<void> deleteOutProvinceStewardFreeBar({
required String token,
required String key,
});
Future<UserProfile?> getUserProfile({required String token});
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
});
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
});
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
});
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
});
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
});
Future<BroadcastPrice?> getBroadcastPrice({required String token});
Future<StewardSalesInfoDashboard?> getStewardSalesInfoDashboard({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<StewardRemainWeight?> getStewardRemainWeight({required String token});
}

View File

@@ -1,94 +0,0 @@
import 'package:rasadyar_chicken/data/models/poultry_export/poultry_export.dart';
import 'package:rasadyar_chicken/data/models/request/kill_registration/kill_registration.dart';
import 'package:rasadyar_chicken/data/models/response/all_poultry/all_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/approved_price/approved_price.dart';
import 'package:rasadyar_chicken/data/models/response/hatching/hatching_models.dart';
import 'package:rasadyar_chicken/data/models/response/hatching_report/hatching_report.dart';
import 'package:rasadyar_chicken/data/models/response/kill_house_poultry/kill_house_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/kill_request_poultry/kill_request_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_farm/poultry_farm.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_hatching/poultry_hatching.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_order/poultry_order.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_science/home_poultry_science/home_poultry_science_model.dart';
import 'package:rasadyar_chicken/data/models/response/sell_for_freezing/sell_for_freezing.dart';
import 'package:rasadyar_core/core.dart';
abstract class PoultryScienceRemoteDatasource {
Future<HomePoultryScienceModel?> getHomePoultryScience({
required String token,
required String type,
});
Future<PaginationModel<HatchingModel>?> getHatchingPoultry({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> submitPoultryScienceReport({
required String token,
required FormData data,
ProgressCallback? onSendProgress,
});
Future<PaginationModel<HatchingReport>?> getPoultryScienceReport({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<PoultryFarm>?> getPoultryScienceFarmList({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<ApprovedPrice?> getApprovedPrice({ required String token,
Map<String, dynamic>? queryParameters,});
Future<List<AllPoultry>?> getAllPoultry({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<SellForFreezing?> getSellForFreezing({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PoultryExport?> getPoultryExport({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<List<KillRequestPoultry>?> getUserPoultry({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<List<PoultryHatching>?> getPoultryHatching({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<List<KillHousePoultry>?> getKillHouseList({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> submitKillRegistration({
required String token,
required KillRegistrationRequest request,
});
Future<PaginationModel<PoultryOrder>?> getPoultryOderList({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> deletePoultryOder({
required String token,
required String orderId,
});
}

View File

@@ -1,23 +1,19 @@
import 'package:rasadyar_chicken/chicken.dart';
import 'package:rasadyar_chicken/data/common/dio_error_handler.dart';
import 'package:rasadyar_chicken/data/data_source/local/chicken_local.dart';
import 'package:rasadyar_chicken/data/data_source/local/chicken_local_imp.dart';
import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote.dart';
import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote_imp.dart';
import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote.dart';
import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote_imp.dart';
import 'package:rasadyar_chicken/features/common/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/common/data/di/common_di.dart';
import 'package:rasadyar_chicken/data/data_source/remote/kill_house/kill_house_remote.dart';
import 'package:rasadyar_chicken/data/data_source/remote/kill_house/kill_house_remote_impl.dart';
import 'package:rasadyar_chicken/data/data_source/remote/poultry_science/poultry_science_remote.dart';
import 'package:rasadyar_chicken/data/data_source/remote/poultry_science/poultry_science_remote_imp.dart';
import 'package:rasadyar_chicken/data/repositories/auth/auth_repository.dart';
import 'package:rasadyar_chicken/data/repositories/auth/auth_repository_imp.dart';
import 'package:rasadyar_chicken/data/repositories/chicken/chicken_repository.dart';
import 'package:rasadyar_chicken/data/repositories/chicken/chicken_repository_imp.dart';
import 'package:rasadyar_chicken/data/repositories/kill_house/kill_house_repository.dart';
import 'package:rasadyar_chicken/data/repositories/kill_house/kill_house_repository_impl.dart';
import 'package:rasadyar_chicken/data/repositories/poultry_science/poultry_science_repository.dart';
import 'package:rasadyar_chicken/data/repositories/poultry_science/poultry_science_repository_imp.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/di/poultry_science_di.dart';
import 'package:rasadyar_chicken/features/steward/data/di/steward_di.dart';
import 'package:rasadyar_chicken/features/province_operator/data/di/province_operator_di.dart';
import 'package:rasadyar_chicken/features/province_inspector/data/di/province_inspector_di.dart';
import 'package:rasadyar_chicken/features/city_jahad/data/di/city_jahad_di.dart';
import 'package:rasadyar_chicken/features/vet_farm/data/di/vet_farm_di.dart';
import 'package:rasadyar_chicken/features/super_admin/data/di/super_admin_di.dart';
import 'package:rasadyar_chicken/features/province_supervisor/data/di/province_supervisor_di.dart';
import 'package:rasadyar_chicken/features/jahad/data/di/jahad_di.dart';
import 'package:rasadyar_core/core.dart';
GetIt diChicken = GetIt.asNewInstance();
@@ -40,7 +36,7 @@ Future<void> setupChickenDI() async {
},
clearTokenCallback: () async {
await tokenService.deleteModuleTokens(Module.chicken);
Get.offAllNamed(ChickenRoutes.auth, arguments: Module.chicken);
Get.offAllNamed(CommonRoutes.auth, arguments: Module.chicken);
},
),
instanceName: 'chickenInterceptor',
@@ -60,47 +56,42 @@ Future<void> setupChickenDI() async {
final dioRemote = diChicken.get<DioRemote>();
await dioRemote.init();
diChicken.registerLazySingleton<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImp(dioRemote),
);
// Setup common feature DI
await setupCommonDI(diChicken, dioRemote);
diChicken.registerLazySingleton<AuthRepository>(
() => AuthRepositoryImpl(diChicken.get<AuthRemoteDataSource>()),
);
// Setup poultry_science feature DI
await setupPoultryScienceDI(diChicken, dioRemote);
diChicken.registerLazySingleton<ChickenRemoteDatasource>(
() => ChickenRemoteDatasourceImp(diChicken.get<DioRemote>()),
);
// Setup steward feature DI
await setupStewardDI(diChicken, dioRemote);
diChicken.registerLazySingleton<ChickenLocalDataSource>(
() => ChickenLocalDataSourceImp(),
);
// Setup province_operator feature DI
await setupProvinceOperatorDI(diChicken, dioRemote);
diChicken.registerLazySingleton<ChickenRepository>(
() => ChickenRepositoryImp(
remote: diChicken.get<ChickenRemoteDatasource>(),
local: diChicken.get<ChickenLocalDataSource>(),
),
);
// Setup province_inspector feature DI
await setupProvinceInspectorDI(diChicken, dioRemote);
diChicken.registerLazySingleton<PoultryScienceRemoteDatasource>(
() => PoultryScienceRemoteDatasourceImp(diChicken.get<DioRemote>()),
);
// Setup city_jahad feature DI
await setupCityJahadDI(diChicken, dioRemote);
diChicken.registerLazySingleton<PoultryScienceRepository>(
() => PoultryScienceRepositoryImp(
diChicken.get<PoultryScienceRemoteDatasource>(),
),
);
// Setup vet_farm feature DI
await setupVetFarmDI(diChicken, dioRemote);
// Setup super_admin feature DI
await setupSuperAdminDI(diChicken, dioRemote);
// Setup province_supervisor feature DI
await setupProvinceSupervisorDI(diChicken, dioRemote);
// Setup jahad feature DI
await setupJahadDI(diChicken, dioRemote);
//region kill house module DI
diChicken.registerLazySingleton<KillHouseRemoteDataSource>(
() => KillHouseRemoteDataSourceImpl(diChicken.get<DioRemote>()),
);
diChicken.registerLazySingleton<KillHouseRepository>(
() => KillHouseRepositoryImpl(
diChicken.get<KillHouseRemoteDataSource>(),
),
() => KillHouseRepositoryImpl(diChicken.get<KillHouseRemoteDataSource>()),
);
//endregion
}
@@ -108,35 +99,26 @@ Future<void> setupChickenDI() async {
Future<void> newSetupAuthDI(String newUrl) async {
var tokenService = Get.find<TokenStorageService>();
// همیشه baseUrl جدید رو ذخیره کن
await tokenService.saveBaseUrl(Module.chicken, newUrl);
// Re-register AppInterceptor
if (diChicken.isRegistered<AppInterceptor>(
instanceName: 'chickenInterceptor',
)) {
await diChicken.unregister<AppInterceptor>(
instanceName: 'chickenInterceptor',
);
}
// پاک‌سازی DI مخصوص ماژول مرغ
await diChicken.resetScope();
diChicken.pushNewScope();
// --- Re-register AppInterceptor
diChicken.registerLazySingleton<AppInterceptor>(
() => AppInterceptor(
refreshTokenCallback: () async => null,
saveTokenCallback: (String newToken) async {
// await tokenService.saveAccessToken(newToken);
},
saveTokenCallback: (newToken) async {},
clearTokenCallback: () async {
await tokenService.deleteModuleTokens(Module.chicken);
Get.offAllNamed(ChickenRoutes.auth, arguments: Module.chicken);
Get.offAllNamed(CommonRoutes.auth, arguments: Module.chicken);
},
),
instanceName: 'chickenInterceptor',
);
// Re-register DioRemote
if (diChicken.isRegistered<DioRemote>()) {
await diChicken.unregister<DioRemote>();
}
// --- Re-register DioRemote
diChicken.registerLazySingleton<DioRemote>(
() => DioRemote(
baseUrl: newUrl,
@@ -145,35 +127,21 @@ Future<void> newSetupAuthDI(String newUrl) async {
),
),
);
final dioRemote = diChicken.get<DioRemote>();
await dioRemote.init();
// Re-register dependent layers
await reRegister<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImp(dioRemote),
);
await reRegister<AuthRepository>(
() => AuthRepositoryImpl(diChicken.get<AuthRemoteDataSource>()),
);
await reRegister<ChickenRemoteDatasource>(
() => ChickenRemoteDatasourceImp(dioRemote),
);
await reRegister<ChickenLocalDataSource>(() => ChickenLocalDataSourceImp());
await reRegister<ChickenRepository>(
() => ChickenRepositoryImp(
remote: diChicken.get<ChickenRemoteDatasource>(),
local: diChicken.get<ChickenLocalDataSource>(),
),
);
await reRegister<PoultryScienceRemoteDatasource>(
() => PoultryScienceRemoteDatasourceImp(dioRemote),
);
await reRegister<PoultryScienceRepository>(
() => PoultryScienceRepositoryImp(
diChicken.get<PoultryScienceRemoteDatasource>(),
),
);
// --- common, poultry_science, steward, and other features
await setupCommonDI(diChicken, dioRemote);
await setupPoultryScienceDI(diChicken, dioRemote);
await setupStewardDI(diChicken, dioRemote);
await setupProvinceOperatorDI(diChicken, dioRemote);
await setupProvinceInspectorDI(diChicken, dioRemote);
await setupCityJahadDI(diChicken, dioRemote);
await setupVetFarmDI(diChicken, dioRemote);
await setupSuperAdminDI(diChicken, dioRemote);
await setupProvinceSupervisorDI(diChicken, dioRemote);
await setupJahadDI(diChicken, dioRemote);
}
Future<void> reRegister<T extends Object>(T Function() factory) async {

View File

@@ -1,224 +0,0 @@
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/conform_allocation/conform_allocation.dart';
import 'package:rasadyar_chicken/data/models/request/steward_free_sale_bar/steward_free_sale_bar_request.dart';
import 'package:rasadyar_chicken/data/models/request/submit_steward_allocation/submit_steward_allocation.dart';
import 'package:rasadyar_chicken/data/models/response/allocated_made/allocated_made.dart';
import 'package:rasadyar_chicken/data/models/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/data/models/response/dashboard_kill_house_free_bar/dashboard_kill_house_free_bar.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/data/models/response/imported_loads_model/imported_loads_model.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar/steward_free_bar.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar_dashboard/steward_free_bar_dashboard.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_sale_bar/steward_free_sale_bar.dart';
import 'package:rasadyar_chicken/data/models/response/steward_remain_weight/steward_remain_weight.dart';
import 'package:rasadyar_chicken/data/models/response/steward_sales_info_dashboard/steward_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/data/models/response/user_profile/user_profile.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart'
hide ProductModel;
import 'package:rasadyar_core/core.dart';
import '../../models/request/create_steward_free_bar/create_steward_free_bar.dart';
abstract class ChickenRepository {
//region Remote
Future<List<ProductModel>?> getRolesProducts({
required String token,
CancelToken? cancelToken,
Map<String, dynamic>? queryParameters,
});
//region Steward
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
});
Future<BarInformation?> getGeneralBarInformation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<WaitingArrivalModel>?> getWaitingArrivals({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> setSateForArrivals({
required String token,
required Map<String, dynamic> request,
});
Future<PaginationModel<ImportedLoadsModel>?> getImportedLoadsModel({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<AllocatedMadeModel>?> getAllocatedMade({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> confirmAllocation({
required String token,
required Map<String, dynamic> allocation,
});
Future<void> denyAllocation({
required String token,
required String allocationToken,
});
Future<void> confirmAllAllocation({
required String token,
required List<String> allocationTokens,
});
Future<List<GuildModel>?> getGuilds({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<GuildProfile?> getProfile({required String token});
Future<void> postSubmitStewardAllocation({
required String token,
required SubmitStewardAllocation request,
});
Future<void> deleteStewardAllocation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> updateStewardAllocation({
required String token,
required ConformAllocation request,
});
Future<StewardFreeBarDashboard?> getStewardDashboard({
required String token,
required String stratDate,
required String endDate,
});
Future<DashboardKillHouseFreeBar?> getDashboardKillHouseFreeBar({
required String token,
required String stratDate,
required String endDate,
});
Future<PaginationModel<StewardFreeBar>?>
getStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createStewardPurchasesOutSideOfTheProvince({
required String token,
required CreateStewardFreeBar body,
});
Future<CreateStewardFreeBar?> editStewardPurchasesOutSideOfTheProvince({
required String token,
required CreateStewardFreeBar body,
});
Future<void> deleteStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<OutProvinceCarcassesBuyer>?>
getOutProvinceCarcassesBuyer({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createOutProvinceCarcassesBuyer({
required String token,
required OutProvinceCarcassesBuyer body,
});
Future<List<IranProvinceCityModel>?> getProvince({CancelToken? cancelToken});
Future<List<IranProvinceCityModel>?> getCity({required String provinceName});
Future<PaginationModel<StewardFreeSaleBar>?> getStewardFreeSaleBar({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createOutProvinceStewardFreeBar({
required String token,
required StewardFreeSaleBarRequest body,
});
Future<void> updateOutProvinceStewardFreeBar({
required String token,
required StewardFreeSaleBarRequest body,
});
Future<void> deleteOutProvinceStewardFreeBar({
required String token,
required String key,
});
Future<UserProfile?> getUserProfile({required String token});
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
});
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
});
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
});
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
});
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
});
Future<BroadcastPrice?> getBroadcastPrice({required String token});
Future<StewardSalesInfoDashboard?> getStewardSalesInfoDashboard({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<StewardRemainWeight?> getStewardRemainWeight({required String token});
//endregion
//endregion
//region local
Future<void> initWidleyUsed();
WidelyUsedLocalModel? getAllWidely();
//endregion
}

View File

@@ -1,434 +0,0 @@
import 'package:rasadyar_chicken/data/data_source/local/chicken_local.dart';
import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote.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/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/steward_free_sale_bar/steward_free_sale_bar_request.dart';
import 'package:rasadyar_chicken/data/models/request/submit_steward_allocation/submit_steward_allocation.dart';
import 'package:rasadyar_chicken/data/models/response/allocated_made/allocated_made.dart';
import 'package:rasadyar_chicken/data/models/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/data/models/response/dashboard_kill_house_free_bar/dashboard_kill_house_free_bar.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/data/models/response/imported_loads_model/imported_loads_model.dart';
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/data/models/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/data/models/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar/steward_free_bar.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_bar_dashboard/steward_free_bar_dashboard.dart';
import 'package:rasadyar_chicken/data/models/response/steward_free_sale_bar/steward_free_sale_bar.dart';
import 'package:rasadyar_chicken/data/models/response/steward_remain_weight/steward_remain_weight.dart';
import 'package:rasadyar_chicken/data/models/response/steward_sales_info_dashboard/steward_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/data/models/response/user_profile/user_profile.dart';
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart'
hide ProductModel;
import 'package:rasadyar_core/core.dart';
import 'chicken_repository.dart';
class ChickenRepositoryImp implements ChickenRepository {
final ChickenRemoteDatasource remote;
final ChickenLocalDataSource local;
ChickenRepositoryImp({required this.remote, required this.local});
//region Remote
@override
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
}) async {
var res = await remote.getKillHouseDistributionInfo(token: token);
return res;
}
@override
Future<BarInformation?> getGeneralBarInformation({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getGeneralBarInformation(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<PaginationModel<WaitingArrivalModel>?> getWaitingArrivals({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getWaitingArrivals(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<void> setSateForArrivals({
required String token,
required Map<String, dynamic> request,
}) async {
await remote.setSateForArrivals(token: token, request: request);
}
@override
Future<PaginationModel<ImportedLoadsModel>?> getImportedLoadsModel({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getImportedLoadsModel(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<PaginationModel<AllocatedMadeModel>?> getAllocatedMade({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getAllocatedMade(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<void> confirmAllocation({
required String token,
required Map<String, dynamic> allocation,
}) async {
await remote.confirmAllocation(token: token, allocation: allocation);
}
@override
Future<void> denyAllocation({
required String token,
required String allocationToken,
}) async {
await remote.denyAllocation(token: token, allocationToken: allocationToken);
}
@override
Future<void> confirmAllAllocation({
required String token,
required List<String> allocationTokens,
}) async {
await remote.confirmAllAllocation(
token: token,
allocationTokens: allocationTokens,
);
}
@override
Future<List<ProductModel>?> getRolesProducts({
required String token,
CancelToken? cancelToken,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getRolesProducts(
token: token,
cancelToken: cancelToken,
queryParameters: queryParameters,
);
return res;
}
@override
Future<List<GuildModel>?> getGuilds({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getGuilds(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<GuildProfile?> getProfile({required String token}) async {
var res = await remote.getProfile(token: token);
return res;
}
@override
Future<void> postSubmitStewardAllocation({
required String token,
required SubmitStewardAllocation request,
}) async {
await remote.postSubmitStewardAllocation(token: token, request: request);
}
@override
Future<void> deleteStewardAllocation({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
await remote.deleteStewardAllocation(
token: token,
queryParameters: queryParameters,
);
}
@override
Future<void> updateStewardAllocation({
required String token,
required ConformAllocation request,
}) async {
await remote.updateStewardAllocation(token: token, request: request);
}
@override
Future<StewardFreeBarDashboard?> getStewardDashboard({
required String token,
required String stratDate,
required String endDate,
}) async {
var res = await remote.getStewardDashboard(
token: token,
stratDate: stratDate,
endDate: endDate,
);
return res;
}
@override
Future<DashboardKillHouseFreeBar?> getDashboardKillHouseFreeBar({
required String token,
required String stratDate,
required String endDate,
}) async {
var res = await remote.getDashboardKillHouseFreeBar(
token: token,
stratDate: stratDate,
endDate: endDate,
);
return res;
}
@override
Future<PaginationModel<StewardFreeBar>?>
getStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getStewardPurchasesOutSideOfTheProvince(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<List<IranProvinceCityModel>?> getCity({
required String provinceName,
}) async {
var res = await remote.getCity(provinceName: provinceName);
return res;
}
@override
Future<List<IranProvinceCityModel>?> getProvince({
CancelToken? cancelToken,
}) async {
var res = await remote.getProvince(cancelToken: cancelToken);
return res;
}
@override
Future<void> createStewardPurchasesOutSideOfTheProvince({
required String token,
required CreateStewardFreeBar body,
}) async {
await remote.createStewardPurchasesOutSideOfTheProvince(
token: token,
body: body,
);
}
@override
Future<CreateStewardFreeBar?> editStewardPurchasesOutSideOfTheProvince({
required String token,
required CreateStewardFreeBar body,
}) async {
return await remote.editStewardPurchasesOutSideOfTheProvince(
token: token,
queryParameters: body.toJson()
..removeWhere((key, value) => value == null),
);
}
@override
Future<void> deleteStewardPurchasesOutSideOfTheProvince({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
await remote.deleteStewardPurchasesOutSideOfTheProvince(
token: token,
queryParameters: queryParameters,
);
}
@override
Future<PaginationModel<OutProvinceCarcassesBuyer>?>
getOutProvinceCarcassesBuyer({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getOutProvinceCarcassesBuyer(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<void> createOutProvinceCarcassesBuyer({
required String token,
required OutProvinceCarcassesBuyer body,
}) async {
await remote.createOutProvinceCarcassesBuyer(token: token, body: body);
}
@override
Future<PaginationModel<StewardFreeSaleBar>?> getStewardFreeSaleBar({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getStewardFreeSaleBar(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<void> createOutProvinceStewardFreeBar({
required String token,
required StewardFreeSaleBarRequest body,
}) async {
await remote.createOutProvinceStewardFreeBar(token: token, body: body);
}
@override
Future<void> updateOutProvinceStewardFreeBar({
required String token,
required StewardFreeSaleBarRequest body,
}) async {
await remote.updateOutProvinceStewardFreeBar(token: token, body: body);
}
@override
Future<void> deleteOutProvinceStewardFreeBar({
required String token,
required String key,
}) async {
await remote.deleteOutProvinceStewardFreeBar(token: token, key: key);
}
@override
Future<UserProfile?> getUserProfile({required String token}) async {
var res = await remote.getUserProfile(token: token);
return res;
}
@override
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
}) async {
await remote.updateUserProfile(token: token, userProfile: userProfile);
}
@override
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
}) async {
await remote.updatePassword(token: token, model: model);
}
@override
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getSegmentation(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
}) async {
await remote.createSegmentation(token: token, model: model);
}
@override
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
}) async {
await remote.editSegmentation(token: token, model: model);
}
@override
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
}) async {
var res = await remote.deleteSegmentation(token: token, key: key);
return res;
}
@override
Future<BroadcastPrice?> getBroadcastPrice({required String token}) async {
var res = await remote.getBroadcastPrice(token: token);
return res;
}
//endregion
//region local
@override
WidelyUsedLocalModel? getAllWidely() => local.getAllWidely();
@override
Future<void> initWidleyUsed() async {
await local.initWidleyUsed();
}
@override
Future<StewardSalesInfoDashboard?> getStewardSalesInfoDashboard({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await remote.getStewardSalesInfoDashboard(
token: token,
queryParameters: queryParameters,
);
}
@override
Future<StewardRemainWeight?> getStewardRemainWeight({
required String token,
}) async {
return await remote.getStewardRemainWeight(token: token);
}
//endregion
}

View File

@@ -1,91 +0,0 @@
import 'package:rasadyar_chicken/data/models/poultry_export/poultry_export.dart';
import 'package:rasadyar_chicken/data/models/request/kill_registration/kill_registration.dart';
import 'package:rasadyar_chicken/data/models/response/all_poultry/all_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/approved_price/approved_price.dart';
import 'package:rasadyar_chicken/data/models/response/hatching/hatching_models.dart';
import 'package:rasadyar_chicken/data/models/response/hatching_report/hatching_report.dart';
import 'package:rasadyar_chicken/data/models/response/kill_house_poultry/kill_house_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/kill_request_poultry/kill_request_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_farm/poultry_farm.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_hatching/poultry_hatching.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_order/poultry_order.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_science/home_poultry_science/home_poultry_science_model.dart';
import 'package:rasadyar_chicken/data/models/response/sell_for_freezing/sell_for_freezing.dart';
import 'package:rasadyar_core/core.dart';
abstract class PoultryScienceRepository {
Future<HomePoultryScienceModel?> getHomePoultry({required String token, required String type});
Future<PaginationModel<HatchingModel>?> getHatchingPoultry({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> submitPoultryScienceReport({
required String token,
required FormData data,
ProgressCallback? onSendProgress,
});
Future<PaginationModel<HatchingReport>?> getHatchingPoultryReport({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PaginationModel<PoultryFarm>?> getPoultryScienceFarmList({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<ApprovedPrice?> getApprovedPrice({ required String token,
Map<String, dynamic>? queryParameters,});
Future<List<AllPoultry>?> getAllPoultry({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<SellForFreezing?> getSellForFreezing({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<PoultryExport?> getPoultryExport({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<List<KillRequestPoultry>?> getUserPoultry({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<List<PoultryHatching>?> getPoultryHatching({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<List<KillHousePoultry>?> getKillHouseList({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> submitKillRegistration({
required String token,
required KillRegistrationRequest request,
});
Future<PaginationModel<PoultryOrder>?> getPoultryOderList({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> deletePoultryOder({
required String token,
required String orderId,
});
}

View File

@@ -1,145 +0,0 @@
import 'package:rasadyar_chicken/data/data_source/remote/poultry_science/poultry_science_remote.dart';
import 'package:rasadyar_chicken/data/models/poultry_export/poultry_export.dart';
import 'package:rasadyar_chicken/data/models/request/kill_registration/kill_registration.dart';
import 'package:rasadyar_chicken/data/models/response/all_poultry/all_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/approved_price/approved_price.dart';
import 'package:rasadyar_chicken/data/models/response/hatching/hatching_models.dart';
import 'package:rasadyar_chicken/data/models/response/hatching_report/hatching_report.dart';
import 'package:rasadyar_chicken/data/models/response/kill_house_poultry/kill_house_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/kill_request_poultry/kill_request_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_farm/poultry_farm.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_hatching/poultry_hatching.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_order/poultry_order.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_science/home_poultry_science/home_poultry_science_model.dart';
import 'package:rasadyar_chicken/data/models/response/sell_for_freezing/sell_for_freezing.dart';
import 'package:rasadyar_core/core.dart';
import 'poultry_science_repository.dart';
class PoultryScienceRepositoryImp implements PoultryScienceRepository {
final PoultryScienceRemoteDatasource datasource;
PoultryScienceRepositoryImp(this.datasource);
@override
Future<HomePoultryScienceModel?> getHomePoultry({
required String token,
required String type,
}) async => await datasource.getHomePoultryScience(token: token, type: type);
@override
Future<PaginationModel<HatchingModel>?> getHatchingPoultry({
required String token,
Map<String, dynamic>? queryParameters,
}) async => await datasource.getHatchingPoultry(token: token, queryParameters: queryParameters);
@override
Future<void> submitPoultryScienceReport({
required String token,
required FormData data,
ProgressCallback? onSendProgress,
}) async => await datasource.submitPoultryScienceReport(
token: token,
data: data,
onSendProgress: onSendProgress,
);
@override
Future<PaginationModel<HatchingReport>?> getHatchingPoultryReport({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getPoultryScienceReport(token: token, queryParameters: queryParameters);
}
@override
Future<PaginationModel<PoultryFarm>?> getPoultryScienceFarmList({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getPoultryScienceFarmList(
token: token,
queryParameters: queryParameters,
);
}
@override
Future<ApprovedPrice?> getApprovedPrice({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getApprovedPrice(token: token, queryParameters: queryParameters);
}
@override
Future<List<AllPoultry>?> getAllPoultry({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getAllPoultry(token: token, queryParameters: queryParameters);
}
@override
Future<PoultryExport?> getPoultryExport({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getPoultryExport(token: token, queryParameters: queryParameters);
}
@override
Future<SellForFreezing?> getSellForFreezing({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getSellForFreezing(token: token, queryParameters: queryParameters);
}
@override
Future<List<KillRequestPoultry>?> getUserPoultry({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getUserPoultry(token: token, queryParameters: queryParameters);
}
@override
Future<List<PoultryHatching>?> getPoultryHatching({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getPoultryHatching(token: token, queryParameters: queryParameters);
}
@override
Future<List<KillHousePoultry>?> getKillHouseList({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getKillHouseList(token: token, queryParameters: queryParameters);
}
@override
Future<void> submitKillRegistration({
required String token,
required KillRegistrationRequest request,
}) async {
await datasource.submitKillRegistration(token: token, request: request);
}
@override
Future<PaginationModel<PoultryOrder>?> getPoultryOderList({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await datasource.getPoultryOderList(token: token, queryParameters: queryParameters);
}
@override
Future<void> deletePoultryOder({
required String token,
required String orderId,
}) async {
await datasource.deletePoultryOder(token: token, orderId: orderId);
}
}

View File

@@ -0,0 +1,3 @@
export 'data/di/city_jahad_di.dart';
export 'presentation/routes/routes.dart';
export 'presentation/routes/pages.dart';

View File

@@ -0,0 +1,15 @@
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response.dart';
import 'package:rasadyar_core/core.dart';
abstract class CityJahadRemoteDataSource {
Future<PaginationModel<PoultryScienceReport>?> getSubmitInspectionList({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> submitInspection({
required String token,
required SubmitInspectionResponse request,
});
}

View File

@@ -0,0 +1,39 @@
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response.dart';
import 'package:rasadyar_chicken/features/city_jahad/data/datasources/remote/city_jahad_remote_data_source.dart';
import 'package:rasadyar_core/core.dart';
class CityJahadRemoteDataSourceImpl implements CityJahadRemoteDataSource {
final DioRemote _httpClient;
CityJahadRemoteDataSourceImpl(this._httpClient);
@override
Future<PaginationModel<PoultryScienceReport>?> getSubmitInspectionList({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await _httpClient.get(
'/poultry_science_report/',
headers: {'Authorization': 'Bearer $token'},
queryParameters: queryParameters,
fromJson: (json) => PaginationModel<PoultryScienceReport>.fromJson(
json,
(json) => PoultryScienceReport.fromJson(json as Map<String, dynamic>),
),
);
return res.data;
}
@override
Future<void> submitInspection({
required String token,
required SubmitInspectionResponse request,
}) async {
await _httpClient.post(
'/poultry_science_report/',
headers: {'Authorization': 'Bearer $token'},
data: request.toJson(),
);
}
}

View File

@@ -0,0 +1,36 @@
import 'package:rasadyar_chicken/features/city_jahad/data/datasources/remote/city_jahad_remote_data_source.dart';
import 'package:rasadyar_chicken/features/city_jahad/data/datasources/remote/city_jahad_remote_data_source_impl.dart';
import 'package:rasadyar_chicken/features/city_jahad/data/repositories/city_jahad_repository.dart';
import 'package:rasadyar_chicken/features/city_jahad/data/repositories/city_jahad_repository_impl.dart';
import 'package:rasadyar_core/core.dart';
/// Setup dependency injection for city_jahad feature
Future<void> setupCityJahadDI(GetIt di, DioRemote dioRemote) async {
di.registerLazySingleton<CityJahadRemoteDataSource>(
() => CityJahadRemoteDataSourceImpl(dioRemote),
);
di.registerLazySingleton<CityJahadRepository>(
() => CityJahadRepositoryImpl(di.get<CityJahadRemoteDataSource>()),
);
}
/// Re-register city_jahad dependencies (used when base URL changes)
Future<void> reRegisterCityJahadDI(GetIt di, DioRemote dioRemote) async {
await reRegister(di, () => CityJahadRemoteDataSourceImpl(dioRemote));
await reRegister(
di,
() => CityJahadRepositoryImpl(di.get<CityJahadRemoteDataSource>()),
);
}
/// Helper function to re-register a dependency
Future<void> reRegister<T extends Object>(
GetIt di,
T Function() factory,
) async {
if (di.isRegistered<T>()) {
await di.unregister<T>();
}
di.registerLazySingleton<T>(factory);
}

View File

@@ -0,0 +1,15 @@
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response.dart';
import 'package:rasadyar_core/core.dart';
abstract class CityJahadRepository {
Future<PaginationModel<PoultryScienceReport>?> getSubmitInspectionList({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> submitInspection({
required String token,
required SubmitInspectionResponse request,
});
}

View File

@@ -0,0 +1,30 @@
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response.dart';
import 'package:rasadyar_chicken/features/city_jahad/data/datasources/remote/city_jahad_remote_data_source.dart';
import 'package:rasadyar_chicken/features/city_jahad/data/repositories/city_jahad_repository.dart';
import 'package:rasadyar_core/core.dart';
class CityJahadRepositoryImpl implements CityJahadRepository {
final CityJahadRemoteDataSource _remote;
CityJahadRepositoryImpl(this._remote);
@override
Future<PaginationModel<PoultryScienceReport>?> getSubmitInspectionList({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
return await _remote.getSubmitInspectionList(
token: token,
queryParameters: queryParameters,
);
}
@override
Future<void> submitInspection({
required String token,
required SubmitInspectionResponse request,
}) async {
return await _remote.submitInspection(token: token, request: request);
}
}

View File

@@ -0,0 +1,95 @@
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/hatching/hatching_models.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/repositories/poultry_science_repository.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/root/logic.dart';
import 'package:rasadyar_core/core.dart';
class ActiveHatchingLogic extends GetxController {
CityJahadRootLogic rootLogic = Get.find<CityJahadRootLogic>();
BaseLogic baseLogic = Get.find<BaseLogic>();
late PoultryScienceRepository poultryScienceRepository;
Rx<Resource<PaginationModel<HatchingModel>>> activeHatchingList =
Resource<PaginationModel<HatchingModel>>.loading().obs;
final RxBool isLoadingMoreList = false.obs;
RxInt currentPage = 1.obs;
RxInt expandedIndex = RxInt(-1);
List<String> routesName = ['اقدام', 'جوجه ریزی فعال'];
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
RxnString searchedValue = RxnString();
@override
void onInit() {
super.onInit();
poultryScienceRepository = diChicken.get<PoultryScienceRepository>();
}
@override
void onReady() {
super.onReady();
getHatchingList();
}
@override
void onClose() {
super.onClose();
baseLogic.clearSearch();
}
Future<void> getHatchingList([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreList.value = true;
} else {
activeHatchingList.value =
Resource<PaginationModel<HatchingModel>>.loading();
}
if (searchedValue.value != null &&
searchedValue.value!.trim().isNotEmpty &&
currentPage.value > 1) {
currentPage.value = 1;
}
safeCall(
call: () async => await poultryScienceRepository.getHatchingPoultry(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
queryParams: {'type': 'hatching'},
role: 'CityJahad',
pageSize: 50,
page: currentPage.value,
),
),
onSuccess: (res) {
if ((res?.count ?? 0) == 0) {
activeHatchingList.value =
Resource<PaginationModel<HatchingModel>>.empty();
} else {
activeHatchingList.value =
Resource<PaginationModel<HatchingModel>>.success(
PaginationModel<HatchingModel>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: [
...(activeHatchingList.value.data?.results ?? []),
...(res?.results ?? []),
],
),
);
}
},
);
}
void toggleExpanded(int index) {
expandedIndex.value = expandedIndex.value == index ? -1 : index;
}
Future<void> onRefresh() async {
currentPage.value = 1;
await getHatchingList();
}
}

View File

@@ -0,0 +1,239 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/hatching/hatching_models.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/active_hatching/logic.dart';
import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet.dart';
import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
class ActiveHatchingPage extends GetView<ActiveHatchingLogic> {
const ActiveHatchingPage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
hasSearch: true,
hasFilter: false,
backId: cityJahadActionKey,
routes: controller.routesName,
onSearchChanged: (data) {
controller.searchedValue.value = data;
controller.getHatchingList();
},
child: hatchingWidget(),
/*widgets: [
hatchingWidget()
],*/
);
}
Widget hatchingWidget() {
return ObxValue((data) {
return RPaginatedListView(
listType: ListType.separated,
resource: data.value,
hasMore: data.value.data?.next != null,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value.isEqual(index),
onTap: () => controller.toggleExpanded(index),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item),
labelColor: AppColor.blueLight,
labelIcon: Assets.vec.activeFramSvg.path,
);
}, controller.expandedIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async => controller.getHatchingList(true),
);
}, controller.activeHatchingList);
}
Container itemListExpandedWidget(HatchingModel item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
item.poultry?.user?.fullname ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
Spacer(),
Visibility(
child: Text(
item.violation == true ? 'پیگیری' : 'عادی',
textAlign: TextAlign.center,
style: AppFonts.yekan10.copyWith(color: AppColor.redDark),
),
),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'نژاد:${item.breed?.first.breed ?? 'N/A'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
Text(
' سن${item.age} (روز)',
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
Text(
' دوره جوجه ریزی:${item.period}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(
title: 'شماره مجوز جوجه ریزی',
value: item.licenceNumber ?? 'N/A',
),
buildUnitRow(
title: 'حجم جوجه ریزی',
value: item.quantity.separatedByCommaFa,
unit: '(قطعه)',
),
buildUnitRow(
title: 'مانده در سالن',
value: item.leftOver.separatedByCommaFa,
unit: '(قطعه)',
),
buildUnitRow(
title: 'تلفات',
value: item.losses.separatedByCommaFa,
unit: '(قطعه)',
),
buildRow(
title: 'دامپزشک فارم',
value:
'${item.vetFarm?.vetFarmFullName}(${item.vetFarm?.vetFarmMobile})',
),
buildRow(
title: 'شرح بازرسی',
value: item.reportInfo?.image == false
? 'ارسال تصویر جوجه ریزی فارم '
: 'تکمیل شده',
titleStyle: AppFonts.yekan14.copyWith(
color: (item.reportInfo?.image ?? false)
? AppColor.greenNormal
: AppColor.redDark,
),
valueStyle: AppFonts.yekan14.copyWith(
color: (item.reportInfo?.image ?? false)
? AppColor.greenNormal
: AppColor.redDark,
),
),
RElevated(
height: 40.h,
isFullWidth: true,
onPressed: () {
Get.find<CreateInspectionBottomSheetLogic>().setHatchingModel(
item,
);
Get.bottomSheet(
CreateInspectionBottomSheet(),
isScrollControlled: true,
ignoreSafeArea: false,
).then((value) {
if (Get.isRegistered<CreateInspectionBottomSheetLogic>()) {
Get.find<CreateInspectionBottomSheetLogic>().clearForm();
}
});
},
child: Text('ثبت بازرسی'),
),
],
),
);
}
Widget itemListWidget(HatchingModel item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 20),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 3,
children: [
Text(
item.poultry?.user?.fullname ?? 'N/A',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
item.poultry?.user?.mobile ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 3,
child: Column(
spacing: 3,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
item.poultry?.unitName ?? 'N/A',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
Text(
item.poultry?.licenceNumber ?? 'N/A',
textAlign: TextAlign.left,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
],
),
),
Expanded(
flex: 1,
child: Assets.vec.scanSvg.svg(
width: 32.w,
height: 32.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
);
}
}

View File

@@ -0,0 +1,29 @@
import 'package:rasadyar_chicken/features/city_jahad/presentation/routes/routes.dart';
import 'package:rasadyar_core/core.dart';
class CityJahadActionItem {
final String title;
final String route;
final String icon;
CityJahadActionItem({
required this.title,
required this.route,
required this.icon,
});
}
class CityJahadHomeLogic extends GetxController {
RxList<CityJahadActionItem> items = [
CityJahadActionItem(
title: "جوجه ریزی فعال",
route: CityJahadRoutes.activeHatchingCityJahad,
icon: Assets.vec.activeFramSvg.path,
),
CityJahadActionItem(
title: "بازرسی مزارع طیور",
route: CityJahadRoutes.newInspectionCityJahad,
icon: Assets.vec.activeFramSvg.path,
),
].obs;
}

View File

@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class CityJahadHomePage extends GetView<CityJahadHomeLogic> {
CityJahadHomePage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
isBase: true,
hasNews: true,
hasNotification: true,
child: gridWidget(),
);
}
Widget gridWidget() {
return ObxValue((data) {
return GridView.builder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(vertical: 18.h, horizontal: 32.w),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 24.h,
crossAxisSpacing: 24.w,
),
itemCount: data.length,
hitTestBehavior: HitTestBehavior.opaque,
itemBuilder: (BuildContext context, int index) {
var item = data[index];
return GlassMorphismCardIcon(
title: item.title,
vecIcon: item.icon,
onTap: () async {
Get.toNamed(item.route, id: cityJahadActionKey);
},
);
},
);
}, controller.items);
}
}

View File

@@ -0,0 +1,160 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/root/logic.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
import 'package:rasadyar_core/core.dart';
class NewInspectionLogic extends GetxController {
BaseLogic baseLogic = Get.find<BaseLogic>();
Rx<Resource<PaginationModel<PoultryScienceReport>>> submitInspectionList =
Resource<PaginationModel<PoultryScienceReport>>.loading().obs;
CityJahadRootLogic rootLogic = Get.find<CityJahadRootLogic>();
final RxBool isLoadingMoreAllocationsMade = false.obs;
RxInt currentPage = 1.obs;
RxInt expandedIndex = RxInt(-1);
RxList<XFile> pickedImages = <XFile>[].obs;
final List<MultipartFile> _multiPartPickedImages = <MultipartFile>[];
RxBool isOnUpload = false.obs;
RxDouble presentUpload = 0.0.obs;
RxList<String> routesName = RxList();
RxInt selectedSegmentIndex = 0.obs;
RxnString searchedValue = RxnString();
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
@override
void onInit() {
super.onInit();
routesName.value = ['اقدام'].toList();
ever(selectedSegmentIndex, (callback) {
routesName.removeLast();
routesName.add(callback == 0 ? 'بازرسی' : 'بایگانی');
});
}
@override
void onReady() {
super.onReady();
getReport();
}
@override
void onClose() {
super.onClose();
baseLogic.clearSearch();
}
Future<void> getReport([bool isLoadingMore = false]) async {
if (isLoadingMore) {
isLoadingMoreAllocationsMade.value = true;
} else {
submitInspectionList.value =
Resource<PaginationModel<PoultryScienceReport>>.loading();
}
if (searchedValue.value != null &&
searchedValue.value!.trim().isNotEmpty &&
currentPage.value > 1) {
currentPage.value = 1;
}
safeCall(
call: () async =>
await rootLogic.cityJahadRepository.getSubmitInspectionList(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
role: 'CityJahad',
pageSize: 50,
search: 'filter',
page: currentPage.value,
),
),
onSuccess: (res) {
if ((res?.count ?? 0) == 0) {
submitInspectionList.value =
Resource<PaginationModel<PoultryScienceReport>>.empty();
} else {
submitInspectionList.value =
Resource<PaginationModel<PoultryScienceReport>>.success(
PaginationModel<PoultryScienceReport>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
results: [
...(submitInspectionList.value.data?.results ?? []),
...(res?.results ?? []),
],
),
);
}
},
);
}
Future<void> pickImages() async {
determineCurrentPosition();
var tmp = await pickCameraImage();
if (tmp?.path != null && pickedImages.length < 7) {
pickedImages.add(tmp!);
}
}
void removeImage(int index) {
pickedImages.removeAt(index);
}
void closeBottomSheet() {
Get.back();
}
double calculateUploadProgress({required int sent, required int total}) {
if (total != 0) {
double progress = (sent * 100 / total) / 100;
return progress;
} else {
return 0.0;
}
}
void toggleExpanded(int index) {
expandedIndex.value = expandedIndex.value == index ? -1 : index;
}
void setSearchValue(String? data) {
dLog('Search Value: $data');
searchedValue.value = data?.trim();
getReport();
}
Future<void> onRefresh() async {
currentPage.value = 1;
await getReport();
}
String getStatus(PoultryScienceReport item) {
final status = item.reportInformation?.inspectionStatus ?? item.state;
if (status == null || status.isEmpty) {
return 'در حال بررسی';
}
return status;
}
Color getStatusColor(PoultryScienceReport item) {
final status = item.reportInformation?.inspectionStatus ?? item.state;
if (status == null || status.isEmpty) {
return AppColor.yellowNormal;
}
// می‌توانید منطق رنگ را بر اساس inspectionStatus تنظیم کنید
return AppColor.greenNormal;
}
}

View File

@@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/features/city_jahad/data/repositories/city_jahad_repository.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/routes/pages.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/home/view.dart';
import 'package:rasadyar_chicken/features/common/presentation/page/profile/view.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';
enum ErrorLocationType { serviceDisabled, permissionDenied, none }
class CityJahadRootLogic extends GetxController {
var tokenService = Get.find<TokenStorageService>();
late CityJahadRepository cityJahadRepository;
RxList<ErrorLocationType> errorLocationType = RxList();
RxMap<int, dynamic> homeExpandedList = RxMap();
DateTime? _lastBackPressed;
RxInt currentPage = 0.obs;
final pages = [
Navigator(
key: Get.nestedKey(cityJahadActionKey),
onGenerateRoute: (settings) {
final page = CityJahadPages.pages.firstWhere(
(e) => e.name == settings.name,
orElse: () => CityJahadPages.pages.firstWhere(
(e) => e.name == CityJahadRoutes.homeCityJahad,
),
);
return buildRouteFromGetPage(page);
},
),
ProfilePage(),
];
@override
void onInit() {
super.onInit();
cityJahadRepository = diChicken.get<CityJahadRepository>();
}
void toggleExpanded(int index) {
if (homeExpandedList.keys.contains(index)) {
homeExpandedList.remove(index);
} else {
homeExpandedList[index] = false;
}
}
void rootErrorHandler(DioException error) {
handleGeneric(error, () {
tokenService.deleteModuleTokens(Module.chicken);
});
}
void changePage(int index) {
currentPage.value = index;
}
void popBackTaped() async {
final now = DateTime.now();
if (_lastBackPressed == null ||
now.difference(_lastBackPressed!) > Duration(seconds: 2)) {
_lastBackPressed = now;
Get.snackbar(
'خروج از برنامه',
'برای خروج دوباره بازگشت را بزنید',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 2),
backgroundColor: AppColor.warning,
);
} else {
await SystemNavigator.pop();
}
}
}

View File

@@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class CityJahadRootPage extends GetView<CityJahadRootLogic> {
const CityJahadRootPage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
isFullScreen: true,
onPopScopTaped: controller.popBackTaped,
child: ObxValue((data) {
return Stack(
children: [
IndexedStack(children: controller.pages, index: data.value),
Positioned(
right: 0,
left: 0,
bottom: 0,
child: RBottomNavigation(
mainAxisAlignment: MainAxisAlignment.spaceAround,
items: [
RBottomNavigationItem(
label: 'خانه',
icon: Assets.vec.homeSvg.path,
isSelected: controller.currentPage.value == 0,
onTap: () {
Get.nestedKey(
cityJahadActionKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(0);
},
),
RBottomNavigationItem(
label: 'پروفایل',
icon: Assets.vec.profileCircleSvg.path,
isSelected: controller.currentPage.value == 1,
onTap: () {
Get.nestedKey(
cityJahadActionKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(1);
},
),
],
),
),
],
);
}, controller.currentPage),
);
}
}

View File

@@ -0,0 +1,66 @@
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/home/logic.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/home/view.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/root/logic.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/root/view.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/active_hatching/logic.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/active_hatching/view.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/new_inspection/logic.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/pages/new_inspection/view.dart';
import 'package:rasadyar_chicken/features/city_jahad/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart';
import 'package:rasadyar_chicken/presentation/routes/global_binding.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
import 'package:rasadyar_core/core.dart';
class CityJahadPages {
CityJahadPages._();
static List<GetPage> get pages => [
GetPage(
name: CityJahadRoutes.initCityJahad,
page: () => CityJahadRootPage(),
middlewares: [AuthMiddleware()],
bindings: [
GlobalBinding(),
BindingsBuilder(() {
Get.lazyPut(() => ChickenBaseLogic(), fenix: true);
Get.lazyPut(() => CityJahadRootLogic());
Get.lazyPut(() => CityJahadHomeLogic());
}),
],
),
GetPage(
name: CityJahadRoutes.homeCityJahad,
page: () => CityJahadHomePage(),
middlewares: [AuthMiddleware()],
binding: BindingsBuilder(() {
Get.put(CityJahadHomeLogic());
Get.lazyPut(() => ChickenBaseLogic());
}),
),
GetPage(
name: CityJahadRoutes.activeHatchingCityJahad,
page: () => ActiveHatchingPage(),
middlewares: [AuthMiddleware()],
bindings: [
GlobalBinding(),
BindingsBuilder(() {
Get.lazyPut(() => ActiveHatchingLogic());
Get.lazyPut(() => CreateInspectionBottomSheetLogic());
}),
],
),
GetPage(
name: CityJahadRoutes.newInspectionCityJahad,
page: () => NewInspectionPage(),
middlewares: [AuthMiddleware()],
bindings: [
GlobalBinding(),
BindingsBuilder(() {
Get.lazyPut(() => NewInspectionLogic());
}),
],
),
];
}

View File

@@ -0,0 +1,10 @@
sealed class CityJahadRoutes {
CityJahadRoutes._();
static const _base = '/chicken/cityJahad';
static const initCityJahad = '$_base/';
static const homeCityJahad = '$_base/home';
static const actionCityJahad = '$_base/action';
static const activeHatchingCityJahad = '$_base/activeHatching';
static const newInspectionCityJahad = '$_base/newInspection';
}

View File

@@ -4,10 +4,11 @@ import 'dart:io';
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/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.dart';
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_info/user_info_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/auth/auth_repository.dart';
import 'package:rasadyar_chicken/features/common/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/steward/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/widget/captcha/logic.dart';
import 'package:rasadyar_core/core.dart';
@@ -28,7 +29,8 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin {
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>();
@@ -56,12 +58,18 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin {
void onInit() {
super.onInit();
_textAnimationController =
AnimationController(vsync: this, duration: const Duration(milliseconds: 1200))
AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
)
..repeat(reverse: true, count: 2).whenComplete(() {
showCard.value = true;
});
textAnimation = CurvedAnimation(parent: _textAnimationController, curve: Curves.easeInOut);
textAnimation = CurvedAnimation(
parent: _textAnimationController,
curve: Curves.easeInOut,
);
initUserPassData();
getDeviceModel();
@@ -98,7 +106,8 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin {
}
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;
}
@@ -117,13 +126,33 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin {
onSuccess: (result) async {
await gService.saveSelectedModule(_module);
await tokenStorageService.saveModule(_module);
await tokenStorageService.saveAccessToken(_module, result?.accessToken ?? '');
await tokenStorageService.saveRefreshToken(_module, result?.accessToken ?? '');
await tokenStorageService.saveAccessToken(
_module,
result?.accessToken ?? '',
);
await tokenStorageService.saveRefreshToken(
_module,
result?.accessToken ?? '',
);
var tmpRoles = result?.role?.where((element) {
final allowedRoles = {'poultryscience', 'steward', 'killhouse'};
final allowedRoles = {
'poultryscience',
'steward',
'killhouse',
'provinceinspector',
'cityjahad',
'jahad',
'vetfarm',
'provincesupervisor',
'superadmin',
};
final lowerElement = element.toString().toLowerCase().trim();
return allowedRoles.contains(lowerElement);
}).toList();
if (tmpRoles?.length==1) {
await tokenStorageService.saveRoles(_module, tmpRoles ?? []);
}
await tokenStorageService.saveRoles(_module, tmpRoles ?? []);
if (rememberMe.value) {
@@ -142,11 +171,15 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin {
},
);
if (tmpRoles!.length > 1) {
Get.offAndToNamed(ChickenRoutes.role);
Get.offAndToNamed(CommonRoutes.role);
/* if (tmpRoles!.length > 1) {
Get.offAndToNamed(CommonRoutes.role);
} else {
Get.offAllNamed(ChickenRoutes.initSteward);
}
Get.offAllNamed(StewardRoutes.initSteward);
} */
},
onError: (error, stackTrace) {
if (error is DioException) {
@@ -183,7 +216,9 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin {
}
void initUserPassData() {
UserLocalModel? userLocalModel = tokenStorageService.getUserLocal(Module.chicken);
UserLocalModel? userLocalModel = tokenStorageService.getUserLocal(
Module.chicken,
);
if (userLocalModel?.username != null && userLocalModel?.password != null) {
usernameController.value.text = userLocalModel?.username ?? '';
passwordController.value.text = userLocalModel?.password ?? '';
@@ -196,18 +231,14 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin {
if (Platform.isAndroid) {
final info = await deviceInfo.androidInfo;
print('Device: ${info.manufacturer} ${info.model}');
print('Android version: ${info.version.release}');
deviceName.value =
'Device:${info.manufacturer} Model:${info.model} version ${info.version.release}';
} else if (Platform.isIOS) {
final info = await deviceInfo.iosInfo;
print('Device: ${info.utsname.machine} (${info.name})');
print('System version: ${info.systemVersion}');
deviceName.value =
'Device:${info.utsname.machine} Model:${info.model} version ${info.systemVersion}';
} else {
print('Unsupported platform');
}
} else {}
}
}

View File

@@ -43,12 +43,16 @@ class AuthPage extends GetView<AuthLogic> {
Text(
'به سامانه رصدطیور خوش آمدید!',
textAlign: TextAlign.right,
style: AppFonts.yekan25Bold.copyWith(color: AppColor.darkGreyDarkActive),
style: AppFonts.yekan25Bold.copyWith(
color: AppColor.darkGreyDarkActive,
),
),
Text(
'سامانه رصد و پایش زنجیره تامین، تولید و توزیع کالا های اساسی',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyDarkActive),
style: AppFonts.yekan16.copyWith(
color: AppColor.darkGreyDarkActive,
),
),
],
),
@@ -80,7 +84,9 @@ class AuthPage extends GetView<AuthLogic> {
vecPath: Assets.vec.rasadToyorSvg.path,
width: 85.w,
height: 85.h,
titleStyle: AppFonts.yekan20Bold.copyWith(color: Color(0xFF4665AF)),
titleStyle: AppFonts.yekan20Bold.copyWith(
color: Color(0xFF4665AF),
),
title: 'رصدطیور',
),
SizedBox(height: 20.h),
@@ -91,7 +97,9 @@ class AuthPage extends GetView<AuthLogic> {
children: [
TextSpan(
text: 'مطالعه بیانیه ',
style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyDark),
style: AppFonts.yekan16.copyWith(
color: AppColor.darkGreyDark,
),
),
TextSpan(
recognizer: TapGestureRecognizer()
@@ -104,7 +112,9 @@ class AuthPage extends GetView<AuthLogic> {
);
},
text: 'حریم خصوصی',
style: AppFonts.yekan16.copyWith(color: AppColor.blueNormal),
style: AppFonts.yekan16.copyWith(
color: AppColor.blueNormal,
),
),
],
),
@@ -128,6 +138,7 @@ class AuthPage extends GetView<AuthLogic> {
child: Column(
children: [
RTextField(
height: 40.h,
label: 'نام کاربری',
maxLength: 11,
maxLines: 1,
@@ -150,7 +161,8 @@ class AuthPage extends GetView<AuthLogic> {
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
child: Assets.vec.callSvg.svg(width: 12, height: 12),
),
suffixIcon: controller.usernameController.value.text.trim().isNotEmpty
suffixIcon:
controller.usernameController.value.text.trim().isNotEmpty
? clearButton(() {
controller.usernameController.value.clear();
controller.usernameController.refresh();
@@ -165,7 +177,9 @@ class AuthPage extends GetView<AuthLogic> {
return null;
},
style: AppFonts.yekan13,
errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
errorStyle: AppFonts.yekan13.copyWith(
color: AppColor.redNormal,
),
labelStyle: AppFonts.yekan13,
boxConstraints: const BoxConstraints(
maxHeight: 40,
@@ -177,6 +191,7 @@ class AuthPage extends GetView<AuthLogic> {
const SizedBox(height: 26),
ObxValue(
(passwordController) => RTextField(
height: 40.h,
label: 'رمز عبور',
filled: false,
obscure: true,
@@ -199,7 +214,9 @@ class AuthPage extends GetView<AuthLogic> {
return null;
},
style: AppFonts.yekan13,
errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
errorStyle: AppFonts.yekan13.copyWith(
color: AppColor.redNormal,
),
labelStyle: AppFonts.yekan13,
prefixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
@@ -226,19 +243,26 @@ class AuthPage extends GetView<AuthLogic> {
ObxValue((data) {
return Checkbox(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity(horizontal: -4, vertical: 4),
visualDensity: VisualDensity(
horizontal: -4,
vertical: 4,
),
tristate: true,
value: data.value,
onChanged: (value) {
data.value = value ?? false;
},
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
activeColor: AppColor.blueNormal,
);
}, controller.rememberMe),
Text(
'مرا به خاطر بسپار',
style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark),
style: AppFonts.yekan14.copyWith(
color: AppColor.darkGreyDark,
),
),
],
),
@@ -283,11 +307,16 @@ class AuthPage extends GetView<AuthLogic> {
children: [
Text(
'بيانيه حريم خصوصی',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
style: AppFonts.yekan16Bold.copyWith(
color: AppColor.blueNormal,
),
),
Text(
'اطلاعات مربوط به هر شخص، حریم خصوصی وی محسوب می‌شود. حفاظت و حراست از اطلاعات شخصی در سامانه رصد یار، نه تنها موجب حفظ امنیت کاربران می‌شود، بلکه باعث اعتماد بیشتر و مشارکت آنها در فعالیت‌های جاری می‌گردد. هدف از این بیانیه، آگاه ساختن شما درباره ی نوع و نحوه ی استفاده از اطلاعاتی است که در هنگام استفاده از سامانه رصد یار ، از جانب شما دریافت می‌گردد. شرکت هوشمند سازان خود را ملزم به رعایت حریم خصوصی همه شهروندان و کاربران سامانه دانسته و آن دسته از اطلاعات کاربران را که فقط به منظور ارائه خدمات کفایت می‌کند، دریافت کرده و از انتشار آن یا در اختیار قرار دادن آن به دیگران خودداری مینماید.',
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
style: AppFonts.yekan14.copyWith(
color: AppColor.bgDark,
height: 1.8,
),
),
],
),
@@ -307,7 +336,9 @@ class AuthPage extends GetView<AuthLogic> {
children: [
Text(
'چگونگی جمع آوری و استفاده از اطلاعات کاربران',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
style: AppFonts.yekan16Bold.copyWith(
color: AppColor.blueNormal,
),
),
Text(
'''الف: اطلاعاتی که شما خود در اختيار این سامانه قرار می‌دهيد، شامل موارد زيرهستند:
@@ -319,7 +350,10 @@ class AuthPage extends GetView<AuthLogic> {
⦁ تعداد بازدیدهای روزانه در درگاه.
⦁ هدف ما از دریافت این اطلاعات استفاده از آنها در تحلیل عملکرد کاربران درگاه می باشد تا بتوانیم در خدمت رسانی بهتر عمل کنیم.
''',
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
style: AppFonts.yekan14.copyWith(
color: AppColor.bgDark,
height: 1.8,
),
),
],
),
@@ -339,11 +373,16 @@ class AuthPage extends GetView<AuthLogic> {
children: [
Text(
'امنیت اطلاعات',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
style: AppFonts.yekan16Bold.copyWith(
color: AppColor.blueNormal,
),
),
Text(
'متعهدیم که امنیت اطلاعات شما را تضمین نماییم و برای جلوگیری از هر نوع دسترسی غیرمجاز و افشای اطلاعات شما از همه شیوه‌‌های لازم استفاده می‌کنیم تا امنیت اطلاعاتی را که به صورت آنلاین گردآوری می‌کنیم، حفظ شود. لازم به ذکر است در سامانه ما، ممکن است به سایت های دیگری لینک شوید، وقتی که شما از طریق این لینک‌ها از سامانه ما خارج می‌شوید، توجه داشته باشید که ما بر دیگر سایت ها کنترل نداریم و سازمان تعهدی بر حفظ حریم شخصی آنان در سایت مقصد نخواهد داشت و مراجعه کنندگان میبایست به بیانیه حریم شخصی آن سایت ها مراجعه نمایند.',
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8),
style: AppFonts.yekan14.copyWith(
color: AppColor.bgDark,
height: 1.8,
),
),
],
),

View File

@@ -0,0 +1,2 @@
export 'presentation/routes/routes.dart';
export 'presentation/routes/pages.dart';

View File

@@ -1,4 +1,4 @@
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/local/widely_used_local_model.dart';
abstract class ChickenLocalDataSource {
Future<void> openBox();

View File

@@ -1,4 +1,5 @@
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/local/widely_used_local_model.dart';
import 'package:rasadyar_chicken/features/steward/presentation/routes/routes.dart';
import 'package:rasadyar_core/core.dart';
import 'chicken_local.dart';
@@ -22,7 +23,7 @@ class ChickenLocalDataSourceImp implements ChickenLocalDataSource {
color: AppColor.greenLightActive.toARGB32(),
iconColor: AppColor.greenNormal.toARGB32(),
iconPath: Assets.vec.cubeSearchSvg.path,
path: ChickenRoutes.buysInProvinceSteward,
path: StewardRoutes.buysInProvinceSteward,
),
WidelyUsedLocalItem(
index: 1,
@@ -31,7 +32,7 @@ class ChickenLocalDataSourceImp implements ChickenLocalDataSource {
color: AppColor.blueLightActive.toARGB32(),
iconColor: AppColor.blueNormal.toARGB32(),
iconPath: Assets.vec.cubeSvg.path,
path: ChickenRoutes.salesInProvinceSteward,
path: StewardRoutes.salesInProvinceSteward,
),
WidelyUsedLocalItem(
@@ -40,7 +41,7 @@ class ChickenLocalDataSourceImp implements ChickenLocalDataSource {
color: AppColor.blueLightActive.toARGB32(),
iconColor: AppColor.blueNormal.toARGB32(),
iconPath: Assets.vec.cubeRotateSvg.path,
path: ChickenRoutes.buysInProvinceSteward,
path: StewardRoutes.buysInProvinceSteward,
),
]; */
}

View File

@@ -1,6 +1,6 @@
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/features/common/data/model/response/user_info/user_info_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart';
abstract class AuthRemoteDataSource {
Future<UserProfileModel?> login({required Map<String, dynamic> authRequest});
@@ -11,6 +11,6 @@ abstract class AuthRemoteDataSource {
Future<UserInfoModel?> getUserInfo(String phoneNumber);
/// Calls `/steward-app-login/` endpoint with required token and `server` as query param, plus optional extra query parameters.
Future<void> stewardAppLogin({required String token, Map<String, dynamic>? queryParameters});
}

View File

@@ -1,5 +1,5 @@
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/features/common/data/model/response/user_info/user_info_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart';
import 'package:rasadyar_core/core.dart';
import 'auth_remote.dart';

View File

@@ -0,0 +1,75 @@
import 'package:rasadyar_chicken/features/common/data/model/request/change_password/change_password_request_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/inventory/inventory_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/features/steward/data/model/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile/user_profile.dart';
import 'package:rasadyar_core/core.dart';
abstract class CommonRemoteDatasource {
Future<List<InventoryModel>?> getInventory({
required String token,
CancelToken? cancelToken,
});
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
});
Future<BarInformation?> getGeneralBarInformation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<List<ProductModel>?> getRolesProducts({required String token});
Future<List<GuildModel>?> getGuilds({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<GuildProfile?> getProfile({required String token});
Future<List<IranProvinceCityModel>?> getProvince({CancelToken? cancelToken});
Future<List<IranProvinceCityModel>?> getCity({required String provinceName});
Future<UserProfile?> getUserProfile({required String token});
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
});
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
});
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
});
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
});
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
});
Future<BroadcastPrice?> getBroadcastPrice({required String token});
}

View File

@@ -0,0 +1,238 @@
import 'package:rasadyar_chicken/features/common/data/model/request/change_password/change_password_request_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/inventory/inventory_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/features/steward/data/model/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile/user_profile.dart';
import 'package:rasadyar_core/core.dart';
import 'common_remote.dart';
class CommonRemoteDatasourceImp implements CommonRemoteDatasource {
final DioRemote _httpClient;
CommonRemoteDatasourceImp(this._httpClient);
@override
Future<List<InventoryModel>?> getInventory({
required String token,
CancelToken? cancelToken,
}) async {
var res = await _httpClient.get(
'/roles-products/?role=Steward',
headers: {'Authorization': 'Bearer $token'},
fromJsonList: (json) => (json)
.map((item) => InventoryModel.fromJson(item as Map<String, dynamic>))
.toList(),
);
return res.data;
}
@override
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
}) async {
var res = await _httpClient.get(
'/kill-house-distribution-info/?role=Steward',
headers: {'Authorization': 'Bearer $token'},
fromJson: KillHouseDistributionInfo.fromJson,
);
return res.data;
}
@override
Future<BarInformation?> getGeneralBarInformation({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await _httpClient.get(
'/bars_for_kill_house_dashboard/',
queryParameters: queryParameters,
headers: {'Authorization': 'Bearer $token'},
fromJson: BarInformation.fromJson,
);
return res.data;
}
@override
Future<List<ProductModel>?> getRolesProducts({required String token}) async {
var res = await _httpClient.get(
'/roles-products/?role=Steward',
headers: {'Authorization': 'Bearer $token'},
fromJsonList: (json) => json
.map((item) => ProductModel.fromJson(item as Map<String, dynamic>))
.toList(),
);
return res.data;
}
@override
Future<List<GuildModel>?> getGuilds({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await _httpClient.get(
'/guilds/',
queryParameters: queryParameters,
headers: {'Authorization': 'Bearer $token'},
fromJsonList: (json) => json
.map((item) => GuildModel.fromJson(item as Map<String, dynamic>))
.toList(),
);
return res.data;
}
@override
Future<GuildProfile?> getProfile({required String token}) async {
var res = await _httpClient.get(
'/guilds/0/?profile',
headers: {'Authorization': 'Bearer $token'},
fromJson: GuildProfile.fromJson,
);
return res.data;
}
@override
Future<List<IranProvinceCityModel>?> getCity({
required String provinceName,
}) async {
var res = await _httpClient.get(
'/iran_city/',
queryParameters: {'name': provinceName},
fromJsonList: (json) => json
.map(
(item) =>
IranProvinceCityModel.fromJson(item as Map<String, dynamic>),
)
.toList(),
);
return res.data;
}
@override
Future<List<IranProvinceCityModel>?> getProvince({
CancelToken? cancelToken,
}) async {
var res = await _httpClient.get(
'/iran_province/',
fromJsonList: (json) => json
.map(
(item) =>
IranProvinceCityModel.fromJson(item as Map<String, dynamic>),
)
.toList(),
);
return res.data;
}
@override
Future<UserProfile?> getUserProfile({required String token}) async {
var res = await _httpClient.get(
'/system_user_profile/?self-profile',
headers: {'Authorization': 'Bearer $token'},
fromJson: (json) => UserProfile.fromJson(json),
);
return res.data;
}
@override
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
}) async {
await _httpClient.put(
'/system_user_profile/0/',
headers: {'Authorization': 'Bearer $token'},
data: userProfile.toJson()..removeWhere((key, value) => value == null),
);
}
@override
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
}) async {
await _httpClient.post(
'/api/change_password/',
headers: {'Authorization': 'Bearer $token'},
data: model.toJson()..removeWhere((key, value) => value == null),
);
}
@override
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await _httpClient.get(
'/app-segmentation/',
queryParameters: queryParameters,
headers: {'Authorization': 'Bearer $token'},
fromJson: (json) => PaginationModel<SegmentationModel>.fromJson(
json,
(json) => SegmentationModel.fromJson(json as Map<String, dynamic>),
),
);
return res.data;
}
@override
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
}) async {
await _httpClient.post(
'/app-segmentation/',
data: model.toJson()..removeWhere((key, value) => value == null),
headers: {'Authorization': 'Bearer $token'},
);
}
@override
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
}) async {
await _httpClient.put(
'/app-segmentation/0/',
data: model.toJson()..removeWhere((key, value) => value == null),
headers: {'Authorization': 'Bearer $token'},
);
}
@override
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
}) async {
var res = await _httpClient.delete<SegmentationModel?>(
'/app-segmentation/0/',
queryParameters: {'key': key},
headers: {'Authorization': 'Bearer $token'},
fromJson: (json) => SegmentationModel.fromJson(json),
);
return res.data;
}
@override
Future<BroadcastPrice?> getBroadcastPrice({required String token}) async {
var res = await _httpClient.get(
'/broadcast-price/',
headers: {'Authorization': 'Bearer $token'},
fromJson: (json) => BroadcastPrice.fromJson(json),
);
return res.data;
}
}

View File

@@ -0,0 +1,66 @@
import 'package:rasadyar_chicken/features/common/data/datasources/local/chicken_local.dart';
import 'package:rasadyar_chicken/features/common/data/datasources/local/chicken_local_imp.dart';
import 'package:rasadyar_chicken/features/common/data/datasources/remote/auth/auth_remote.dart';
import 'package:rasadyar_chicken/features/common/data/datasources/remote/auth/auth_remote_imp.dart';
import 'package:rasadyar_chicken/features/common/data/datasources/remote/common/common_remote.dart';
import 'package:rasadyar_chicken/features/common/data/datasources/remote/common/common_remote_imp.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/auth/auth_repository.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/auth/auth_repository_imp.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/common/common_repository.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/common/common_repository_imp.dart';
import 'package:rasadyar_core/core.dart';
/// Setup dependency injection for common feature
Future<void> setupCommonDI(GetIt di, DioRemote dioRemote) async {
di.registerLazySingleton<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImp(dioRemote),
);
di.registerLazySingleton<AuthRepository>(
() => AuthRepositoryImpl(di.get<AuthRemoteDataSource>()),
);
di.registerLazySingleton<CommonRemoteDatasource>(
() => CommonRemoteDatasourceImp(dioRemote),
);
di.registerLazySingleton<ChickenLocalDataSource>(
() => ChickenLocalDataSourceImp(),
);
di.registerLazySingleton<CommonRepository>(
() => CommonRepositoryImp(
remote: di.get<CommonRemoteDatasource>(),
local: di.get<ChickenLocalDataSource>(),
),
);
}
/// Re-register common dependencies (used when base URL changes)
Future<void> reRegisterCommonDI(GetIt di, DioRemote dioRemote) async {
await reRegister(di, () => AuthRemoteDataSourceImp(dioRemote));
await reRegister(
di,
() => AuthRepositoryImpl(di.get<AuthRemoteDataSource>()),
);
await reRegister(di, () => CommonRemoteDatasourceImp(dioRemote));
await reRegister(di, () => ChickenLocalDataSourceImp());
await reRegister(
di,
() => CommonRepositoryImp(
remote: di.get<CommonRemoteDatasource>(),
local: di.get<ChickenLocalDataSource>(),
),
);
}
/// Helper function to re-register a dependency
Future<void> reRegister<T extends Object>(
GetIt di,
T Function() factory,
) async {
if (di.isRegistered<T>()) {
await di.unregister<T>();
}
di.registerLazySingleton<T>(factory);
}

View File

@@ -0,0 +1,56 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'inventory_model.freezed.dart';
part 'inventory_model.g.dart';
@freezed
abstract class InventoryModel with _$InventoryModel {
const factory InventoryModel({
int? id,
String? key,
String? createDate,
String? modifyDate,
bool? trash,
String? name,
int? provinceGovernmentalCarcassesQuantity,
int? provinceGovernmentalCarcassesWeight,
int? provinceFreeCarcassesQuantity,
int? provinceFreeCarcassesWeight,
int? receiveGovernmentalCarcassesQuantity,
int? receiveGovernmentalCarcassesWeight,
int? receiveFreeCarcassesQuantity,
int? receiveFreeCarcassesWeight,
int? freeBuyingCarcassesQuantity,
int? freeBuyingCarcassesWeight,
int? totalGovernmentalCarcassesQuantity,
int? totalGovernmentalCarcassesWeight,
int? totalFreeBarsCarcassesQuantity,
int? totalFreeBarsCarcassesWeight,
double? weightAverage,
int? totalCarcassesQuantity,
int? totalCarcassesWeight,
int? freezingQuantity,
int? freezingWeight,
int? lossWeight,
int? outProvinceAllocatedQuantity,
int? outProvinceAllocatedWeight,
int? provinceAllocatedQuantity,
int? provinceAllocatedWeight,
int? realAllocatedQuantity,
int? realAllocatedWeight,
int? coldHouseAllocatedWeight,
int? posAllocatedWeight,
int? segmentationWeight,
int? totalRemainQuantity,
int? totalRemainWeight,
int? freePrice,
int? approvedPrice,
bool? approvedPriceStatus,
int? parentProduct,
int? killHouse,
int? guild,
}) = _InventoryModel; // Changed to _InventoryModel
factory InventoryModel.fromJson(Map<String, dynamic> json) =>
_$InventoryModelFromJson(json);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,127 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'inventory_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_InventoryModel _$InventoryModelFromJson(
Map<String, dynamic> json,
) => _InventoryModel(
id: (json['id'] as num?)?.toInt(),
key: json['key'] as String?,
createDate: json['create_date'] as String?,
modifyDate: json['modify_date'] as String?,
trash: json['trash'] as bool?,
name: json['name'] as String?,
provinceGovernmentalCarcassesQuantity:
(json['province_governmental_carcasses_quantity'] as num?)?.toInt(),
provinceGovernmentalCarcassesWeight:
(json['province_governmental_carcasses_weight'] as num?)?.toInt(),
provinceFreeCarcassesQuantity:
(json['province_free_carcasses_quantity'] as num?)?.toInt(),
provinceFreeCarcassesWeight: (json['province_free_carcasses_weight'] as num?)
?.toInt(),
receiveGovernmentalCarcassesQuantity:
(json['receive_governmental_carcasses_quantity'] as num?)?.toInt(),
receiveGovernmentalCarcassesWeight:
(json['receive_governmental_carcasses_weight'] as num?)?.toInt(),
receiveFreeCarcassesQuantity:
(json['receive_free_carcasses_quantity'] as num?)?.toInt(),
receiveFreeCarcassesWeight: (json['receive_free_carcasses_weight'] as num?)
?.toInt(),
freeBuyingCarcassesQuantity: (json['free_buying_carcasses_quantity'] as num?)
?.toInt(),
freeBuyingCarcassesWeight: (json['free_buying_carcasses_weight'] as num?)
?.toInt(),
totalGovernmentalCarcassesQuantity:
(json['total_governmental_carcasses_quantity'] as num?)?.toInt(),
totalGovernmentalCarcassesWeight:
(json['total_governmental_carcasses_weight'] as num?)?.toInt(),
totalFreeBarsCarcassesQuantity:
(json['total_free_bars_carcasses_quantity'] as num?)?.toInt(),
totalFreeBarsCarcassesWeight:
(json['total_free_bars_carcasses_weight'] as num?)?.toInt(),
weightAverage: (json['weight_average'] as num?)?.toDouble(),
totalCarcassesQuantity: (json['total_carcasses_quantity'] as num?)?.toInt(),
totalCarcassesWeight: (json['total_carcasses_weight'] as num?)?.toInt(),
freezingQuantity: (json['freezing_quantity'] as num?)?.toInt(),
freezingWeight: (json['freezing_weight'] as num?)?.toInt(),
lossWeight: (json['loss_weight'] as num?)?.toInt(),
outProvinceAllocatedQuantity:
(json['out_province_allocated_quantity'] as num?)?.toInt(),
outProvinceAllocatedWeight: (json['out_province_allocated_weight'] as num?)
?.toInt(),
provinceAllocatedQuantity: (json['province_allocated_quantity'] as num?)
?.toInt(),
provinceAllocatedWeight: (json['province_allocated_weight'] as num?)?.toInt(),
realAllocatedQuantity: (json['real_allocated_quantity'] as num?)?.toInt(),
realAllocatedWeight: (json['real_allocated_weight'] as num?)?.toInt(),
coldHouseAllocatedWeight: (json['cold_house_allocated_weight'] as num?)
?.toInt(),
posAllocatedWeight: (json['pos_allocated_weight'] as num?)?.toInt(),
segmentationWeight: (json['segmentation_weight'] as num?)?.toInt(),
totalRemainQuantity: (json['total_remain_quantity'] as num?)?.toInt(),
totalRemainWeight: (json['total_remain_weight'] as num?)?.toInt(),
freePrice: (json['free_price'] as num?)?.toInt(),
approvedPrice: (json['approved_price'] as num?)?.toInt(),
approvedPriceStatus: json['approved_price_status'] as bool?,
parentProduct: (json['parent_product'] as num?)?.toInt(),
killHouse: (json['kill_house'] as num?)?.toInt(),
guild: (json['guild'] as num?)?.toInt(),
);
Map<String, dynamic> _$InventoryModelToJson(
_InventoryModel instance,
) => <String, dynamic>{
'id': instance.id,
'key': instance.key,
'create_date': instance.createDate,
'modify_date': instance.modifyDate,
'trash': instance.trash,
'name': instance.name,
'province_governmental_carcasses_quantity':
instance.provinceGovernmentalCarcassesQuantity,
'province_governmental_carcasses_weight':
instance.provinceGovernmentalCarcassesWeight,
'province_free_carcasses_quantity': instance.provinceFreeCarcassesQuantity,
'province_free_carcasses_weight': instance.provinceFreeCarcassesWeight,
'receive_governmental_carcasses_quantity':
instance.receiveGovernmentalCarcassesQuantity,
'receive_governmental_carcasses_weight':
instance.receiveGovernmentalCarcassesWeight,
'receive_free_carcasses_quantity': instance.receiveFreeCarcassesQuantity,
'receive_free_carcasses_weight': instance.receiveFreeCarcassesWeight,
'free_buying_carcasses_quantity': instance.freeBuyingCarcassesQuantity,
'free_buying_carcasses_weight': instance.freeBuyingCarcassesWeight,
'total_governmental_carcasses_quantity':
instance.totalGovernmentalCarcassesQuantity,
'total_governmental_carcasses_weight':
instance.totalGovernmentalCarcassesWeight,
'total_free_bars_carcasses_quantity': instance.totalFreeBarsCarcassesQuantity,
'total_free_bars_carcasses_weight': instance.totalFreeBarsCarcassesWeight,
'weight_average': instance.weightAverage,
'total_carcasses_quantity': instance.totalCarcassesQuantity,
'total_carcasses_weight': instance.totalCarcassesWeight,
'freezing_quantity': instance.freezingQuantity,
'freezing_weight': instance.freezingWeight,
'loss_weight': instance.lossWeight,
'out_province_allocated_quantity': instance.outProvinceAllocatedQuantity,
'out_province_allocated_weight': instance.outProvinceAllocatedWeight,
'province_allocated_quantity': instance.provinceAllocatedQuantity,
'province_allocated_weight': instance.provinceAllocatedWeight,
'real_allocated_quantity': instance.realAllocatedQuantity,
'real_allocated_weight': instance.realAllocatedWeight,
'cold_house_allocated_weight': instance.coldHouseAllocatedWeight,
'pos_allocated_weight': instance.posAllocatedWeight,
'segmentation_weight': instance.segmentationWeight,
'total_remain_quantity': instance.totalRemainQuantity,
'total_remain_weight': instance.totalRemainWeight,
'free_price': instance.freePrice,
'approved_price': instance.approvedPrice,
'approved_price_status': instance.approvedPriceStatus,
'parent_product': instance.parentProduct,
'kill_house': instance.killHouse,
'guild': instance.guild,
};

View File

@@ -1,5 +1,5 @@
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/features/common/data/model/response/user_info/user_info_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart';
abstract class AuthRepository {
Future<UserProfileModel?> login({required Map<String, dynamic> authRequest});

View File

@@ -1,6 +1,6 @@
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 'package:rasadyar_chicken/features/common/data/datasources/remote/auth/auth_remote.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_info/user_info_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart';
import 'auth_repository.dart';

View File

@@ -0,0 +1,85 @@
import 'package:rasadyar_chicken/features/common/data/model/local/widely_used_local_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/request/change_password/change_password_request_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/inventory/inventory_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/features/steward/data/model/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile/user_profile.dart';
import 'package:rasadyar_core/core.dart';
abstract class CommonRepository {
//region Remote
Future<List<InventoryModel>?> getInventory({
required String token,
CancelToken? cancelToken,
});
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
});
Future<BarInformation?> getGeneralBarInformation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<List<ProductModel>?> getRolesProducts({required String token});
Future<List<GuildModel>?> getGuilds({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<GuildProfile?> getProfile({required String token});
Future<List<IranProvinceCityModel>?> getProvince({CancelToken? cancelToken});
Future<List<IranProvinceCityModel>?> getCity({required String provinceName});
Future<UserProfile?> getUserProfile({required String token});
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
});
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
});
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
});
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
});
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
});
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
});
Future<BroadcastPrice?> getBroadcastPrice({required String token});
//endregion
//region local
Future<void> initWidleyUsed();
WidelyUsedLocalModel? getAllWidely();
//endregion
}

View File

@@ -0,0 +1,172 @@
import 'package:rasadyar_chicken/features/common/data/datasources/local/chicken_local.dart';
import 'package:rasadyar_chicken/features/common/data/datasources/remote/common/common_remote.dart';
import 'package:rasadyar_chicken/features/common/data/model/local/widely_used_local_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/request/change_password/change_password_request_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/bar_information/bar_information.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/inventory/inventory_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/kill_house_distribution_info/kill_house_distribution_info.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/features/steward/data/model/response/segmentation_model/segmentation_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile/user_profile.dart';
import 'package:rasadyar_core/core.dart';
import 'common_repository.dart';
class CommonRepositoryImp implements CommonRepository {
final CommonRemoteDatasource remote;
final ChickenLocalDataSource local;
CommonRepositoryImp({required this.remote, required this.local});
//region Remote
@override
Future<List<InventoryModel>?> getInventory({
required String token,
CancelToken? cancelToken,
}) async {
var res = await remote.getInventory(token: token, cancelToken: cancelToken);
return res;
}
@override
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
required String token,
}) async {
var res = await remote.getKillHouseDistributionInfo(token: token);
return res;
}
@override
Future<BarInformation?> getGeneralBarInformation({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getGeneralBarInformation(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<List<ProductModel>?> getRolesProducts({required String token}) async {
var res = await remote.getRolesProducts(token: token);
return res;
}
@override
Future<List<GuildModel>?> getGuilds({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getGuilds(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<GuildProfile?> getProfile({required String token}) async {
var res = await remote.getProfile(token: token);
return res;
}
@override
Future<List<IranProvinceCityModel>?> getCity({
required String provinceName,
}) async {
var res = await remote.getCity(provinceName: provinceName);
return res;
}
@override
Future<List<IranProvinceCityModel>?> getProvince({
CancelToken? cancelToken,
}) async {
var res = await remote.getProvince(cancelToken: cancelToken);
return res;
}
@override
Future<UserProfile?> getUserProfile({required String token}) async {
var res = await remote.getUserProfile(token: token);
return res;
}
@override
Future<void> updateUserProfile({
required String token,
required UserProfile userProfile,
}) async {
await remote.updateUserProfile(token: token, userProfile: userProfile);
}
@override
Future<void> updatePassword({
required String token,
required ChangePasswordRequestModel model,
}) async {
await remote.updatePassword(token: token, model: model);
}
@override
Future<PaginationModel<SegmentationModel>?> getSegmentation({
required String token,
Map<String, dynamic>? queryParameters,
}) async {
var res = await remote.getSegmentation(
token: token,
queryParameters: queryParameters,
);
return res;
}
@override
Future<void> createSegmentation({
required String token,
required SegmentationModel model,
}) async {
await remote.createSegmentation(token: token, model: model);
}
@override
Future<void> editSegmentation({
required String token,
required SegmentationModel model,
}) async {
await remote.editSegmentation(token: token, model: model);
}
@override
Future<SegmentationModel?> deleteSegmentation({
required String token,
required String key,
}) async {
var res = await remote.deleteSegmentation(token: token, key: key);
return res;
}
@override
Future<BroadcastPrice?> getBroadcastPrice({required String token}) async {
var res = await remote.getBroadcastPrice(token: token);
return res;
}
//endregion
//region local
@override
WidelyUsedLocalModel? getAllWidely() => local.getAllWidely();
@override
Future<void> initWidleyUsed() async {
await local.initWidleyUsed();
}
//endregion
}

View File

@@ -0,0 +1,244 @@
import 'dart:async';
import 'dart:io';
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/features/common/data/model/response/user_info/user_info_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/auth/auth_repository.dart';
import 'package:rasadyar_chicken/features/common/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/steward/presentation/routes/routes.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;
RxBool rememberMe = 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;
GService gService = Get.find<GService>();
TokenStorageService tokenStorageService = Get.find<TokenStorageService>();
Rx<AuthType> authType = AuthType.useAndPass.obs;
Rx<AuthStatus> authStatus = AuthStatus.init.obs;
Rx<OtpStatus> otpStatus = OtpStatus.init.obs;
RxnString deviceName = RxnString(null);
RxInt secondsRemaining = 120.obs;
Timer? _timer;
AuthRepository authRepository = diChicken.get<AuthRepository>();
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,
);
initUserPassData();
getDeviceModel();
}
@override
void onClose() {
_textAnimationController.dispose();
_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;
}
Future<void> submitLoginForm() async {
if (!_isFormValid()) return;
AuthRepository authTmp = diChicken.get<AuthRepository>();
isLoading.value = true;
await safeCall<UserProfileModel?>(
call: () => authTmp.login(
authRequest: {
"username": usernameController.value.text,
"password": passwordController.value.text,
},
),
onSuccess: (result) async {
await gService.saveSelectedModule(_module);
await tokenStorageService.saveModule(_module);
await tokenStorageService.saveAccessToken(
_module,
result?.accessToken ?? '',
);
await tokenStorageService.saveRefreshToken(
_module,
result?.accessToken ?? '',
);
var tmpRoles = result?.role?.where((element) {
final allowedRoles = {
'poultryscience',
'steward',
'killhouse',
'provinceinspector',
'cityjahad',
'jahad',
'vetfarm',
'provincesupervisor',
'superadmin',
};
final lowerElement = element.toString().toLowerCase().trim();
return allowedRoles.contains(lowerElement);
}).toList();
if (tmpRoles?.length==1) {
await tokenStorageService.saveRoles(_module, tmpRoles ?? []);
}
await tokenStorageService.saveRoles(_module, tmpRoles ?? []);
if (rememberMe.value) {
await tokenStorageService.saveUserPass(
_module,
usernameController.value.text,
passwordController.value.text,
);
}
authTmp.stewardAppLogin(
token: result?.accessToken ?? '',
queryParameters: {
"mobile": usernameController.value.text,
"device_name": deviceName.value,
},
);
Get.offAndToNamed(CommonRoutes.role);
/* if (tmpRoles!.length > 1) {
Get.offAndToNamed(CommonRoutes.role);
} else {
Get.offAllNamed(StewardRoutes.initSteward);
} */
},
onError: (error, stackTrace) {
if (error is DioException) {
diChicken.get<DioErrorHandler>().handle(error);
if ((error.type == DioExceptionType.unknown) ||
(error.type == DioExceptionType.connectionError)) {
getUserInfo(usernameController.value.text);
}
}
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 diChicken.allReady();
}
},
onError: (error, stackTrace) {
if (error is DioException) {
diChicken.get<DioErrorHandler>().handle(error);
}
captchaController.getCaptcha();
},
);
isLoading.value = false;
}
void initUserPassData() {
UserLocalModel? userLocalModel = tokenStorageService.getUserLocal(
Module.chicken,
);
if (userLocalModel?.username != null && userLocalModel?.password != null) {
usernameController.value.text = userLocalModel?.username ?? '';
passwordController.value.text = userLocalModel?.password ?? '';
rememberMe.value = true;
}
}
Future<void> getDeviceModel() async {
final deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) {
final info = await deviceInfo.androidInfo;
deviceName.value =
'Device:${info.manufacturer} Model:${info.model} version ${info.version.release}';
} else if (Platform.isIOS) {
final info = await deviceInfo.iosInfo;
deviceName.value =
'Device:${info.utsname.machine} Model:${info.model} version ${info.systemVersion}';
} else {}
}
}

View File

@@ -0,0 +1,394 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.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 ChickenBasePage(
isFullScreen: true,
backGroundWidget: backGroundDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
const Color(0xFFB2C9FF).withValues(alpha: 1.0), // 0%
const Color(0xFF40BB93).withValues(alpha: 0.11), // 50%
const Color(0xFF93B6D3).withValues(alpha: 1.0), // 100%
],
stops: const [0.0, 0.5, 1.0],
),
backgroundPath: Assets.images.patternChicken.path,
),
onPopScopTaped: () => Get.back(result: -1),
child: Stack(
children: [
Center(
child: 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: AppColor.darkGreyDarkActive,
),
),
Text(
'سامانه رصد و پایش زنجیره تامین، تولید و توزیع کالا های اساسی',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(
color: AppColor.darkGreyDarkActive,
),
),
],
),
),
),
),
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(
vecPath: Assets.vec.rasadToyorSvg.path,
width: 85.w,
height: 85.h,
titleStyle: AppFonts.yekan20Bold.copyWith(
color: Color(0xFF4665AF),
),
title: 'رصدطیور',
),
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(
height: 40.h,
label: 'نام کاربری',
maxLength: 11,
maxLines: 1,
controller: controller.usernameController.value,
keyboardType: TextInputType.number,
inputFormatters: [PersianFormatter()],
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(
height: 40.h,
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,
inputFormatters: [PersianFormatter()],
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(),
GestureDetector(
onTap: () {
controller.rememberMe.value = !controller.rememberMe.value;
},
child: Row(
children: [
ObxValue((data) {
return Checkbox(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity(
horizontal: -4,
vertical: 4,
),
tristate: true,
value: data.value,
onChanged: (value) {
data.value = value ?? false;
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
activeColor: AppColor.blueNormal,
);
}, controller.rememberMe),
Text(
'مرا به خاطر بسپار',
style: AppFonts.yekan14.copyWith(
color: AppColor.darkGreyDark,
),
),
],
),
),
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,
),
),
],
),
),
],
),
);
}
}

View File

@@ -0,0 +1,257 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/features/common/data/model/request/change_password/change_password_request_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile/user_profile.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/common/common_repository.dart';
import 'package:rasadyar_core/core.dart';
class ProfileLogic extends GetxController {
CommonRepository commonRepository = diChicken.get<CommonRepository>();
GService gService = Get.find<GService>();
TokenStorageService tokenService = Get.find<TokenStorageService>();
RxInt selectedInformationType = 0.obs;
Rxn<Jalali> birthDate = Rxn<Jalali>();
Rx<Resource<UserProfile>> userProfile = Rx<Resource<UserProfile>>(
Resource.loading(),
);
Rx<Resource<UserLocalModel>> userLocal = Rx<Resource<UserLocalModel>>(
Resource.loading(),
);
TextEditingController nameController = TextEditingController();
TextEditingController lastNameController = TextEditingController();
TextEditingController nationalCodeController = TextEditingController();
TextEditingController nationalIdController = TextEditingController();
TextEditingController birthdayController = TextEditingController();
TextEditingController oldPasswordController = TextEditingController();
TextEditingController newPasswordController = TextEditingController();
TextEditingController retryNewPasswordController = TextEditingController();
RxList<IranProvinceCityModel> cites = <IranProvinceCityModel>[].obs;
Rxn<IranProvinceCityModel> selectedProvince = Rxn();
Rxn<IranProvinceCityModel> selectedCity = Rxn();
GlobalKey<FormState> formKey = GlobalKey();
ImagePicker imagePicker = ImagePicker();
Rxn<XFile> selectedImage = Rxn<XFile>();
final RxnString _base64Image = RxnString();
RxBool isOnLoading = false.obs;
RxBool isUserInformationOpen = true.obs;
RxBool isUnitInformationOpen = false.obs;
ScrollController scrollController = ScrollController();
@override
void onInit() {
super.onInit();
ever(selectedImage, (data) async {
if (data?.path != null) {
_base64Image.value = await convertImageToBase64(data!.path);
}
});
}
@override
void onReady() {
super.onReady();
getUserProfile();
getUserRole();
selectedProvince.listen((p0) => getCites());
userProfile.listen((data) {
nameController.text = data.data?.firstName ?? '';
lastNameController.text = data.data?.lastName ?? '';
nationalCodeController.text = data.data?.nationalCode ?? '';
nationalIdController.text = data.data?.nationalId ?? '';
birthdayController.text =
data.data?.birthday?.toJalali.formatCompactDate() ?? '';
birthDate.value = data.data?.birthday?.toJalali;
selectedProvince.value = IranProvinceCityModel(
name: data.data?.province ?? '',
id: data.data?.provinceNumber ?? 0,
);
selectedCity.value = IranProvinceCityModel(
name: data.data?.city ?? '',
id: data.data?.cityNumber ?? 0,
);
});
}
Future<void> getUserProfile() async {
userProfile.value = Resource.loading();
await safeCall<UserProfile?>(
call: () async => await commonRepository.getUserProfile(
token: tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
userProfile.value = Resource.success(result);
}
},
onError: (error, stackTrace) {},
);
}
Future<void> getCites() async {
await safeCall(
call: () => commonRepository.getCity(
provinceName: selectedProvince.value?.name ?? '',
),
onSuccess: (result) {
if (result != null && result.isNotEmpty) {
cites.value = result;
}
},
);
}
Future<void> updateUserProfile() async {
UserProfile userProfile = UserProfile(
firstName: nameController.text,
lastName: lastNameController.text,
nationalCode: nationalCodeController.text,
nationalId: nationalIdController.text,
birthday: birthDate.value
?.toDateTime()
.formattedDashedGregorian
.toString(),
image: _base64Image.value,
personType: 'self',
type: 'self_profile',
);
isOnLoading.value = true;
await safeCall(
call: () async => await commonRepository.updateUserProfile(
token: tokenService.accessToken.value!,
userProfile: userProfile,
),
onSuccess: (result) {
isOnLoading.value = false;
},
onError: (error, stackTrace) {
isOnLoading.value = false;
},
);
}
Future<void> updatePassword() async {
if (formKey.currentState?.validate() ?? false) {
ChangePasswordRequestModel model = ChangePasswordRequestModel(
username: userProfile.value.data?.mobile,
password: newPasswordController.text,
);
await safeCall(
call: () async => await commonRepository.updatePassword(
token: tokenService.accessToken.value!,
model: model,
),
);
}
}
Future<void> getUserRole() async {
userLocal.value = Resource.loading();
await safeCall<UserLocalModel?>(
call: () async => tokenService.getUserLocal(Module.chicken),
onSuccess: (result) {
if (result != null) {
userLocal.value = Resource.success(result);
}
},
onError: (error, stackTrace) {},
);
}
void clearPasswordForm() {
oldPasswordController.clear();
newPasswordController.clear();
retryNewPasswordController.clear();
}
Future<void> changeUserRole(String newRole) async {
dLog(newRole);
await gService.saveRoute(Module.chicken, newRole);
Get.offAllNamed(newRole);
}
void scrollToSelectedItem(
int index, {
double chipWidth = 100,
double spacing = 8,
GlobalKey? itemKey,
}) {
if (!scrollController.hasClients) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_performScroll(index, chipWidth, spacing, itemKey);
});
} else {
_performScroll(index, chipWidth, spacing, itemKey);
}
}
void _performScroll(
int index,
double chipWidth,
double spacing,
GlobalKey? itemKey,
) {
if (!scrollController.hasClients) return;
double targetOffset;
// If we have a GlobalKey, use it for precise positioning
if (itemKey?.currentContext != null) {
final RenderBox? renderBox =
itemKey!.currentContext?.findRenderObject() as RenderBox?;
if (renderBox != null) {
final position = renderBox.localToGlobal(Offset.zero);
final scrollPosition = scrollController.position;
final viewportWidth = scrollPosition.viewportDimension;
final chipWidth = renderBox.size.width;
// Get the scroll position of the item
final itemScrollPosition = position.dx - scrollPosition.pixels;
// Center the item
targetOffset =
scrollPosition.pixels +
itemScrollPosition -
(viewportWidth / 2) +
(chipWidth / 2);
} else {
// Fallback to estimated position
targetOffset = _calculateEstimatedPosition(index, chipWidth, spacing);
}
} else {
// Use estimated position
targetOffset = _calculateEstimatedPosition(index, chipWidth, spacing);
}
scrollController.animateTo(
targetOffset.clamp(0.0, scrollController.position.maxScrollExtent),
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
double _calculateEstimatedPosition(
int index,
double chipWidth,
double spacing,
) {
final double itemPosition = (chipWidth + spacing) * index;
final double viewportWidth = scrollController.position.viewportDimension;
return itemPosition - (viewportWidth / 2) + (chipWidth / 2);
}
@override
void onClose() {
scrollController.dispose();
super.onClose();
}
}

View File

@@ -0,0 +1,902 @@
import 'dart:io';
import 'package:flutter/cupertino.dart' hide Image;
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/common/fa_user_role.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile/user_profile.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class ProfilePage extends GetView<ProfileLogic> {
const ProfilePage({super.key});
@override
Widget build(BuildContext context) {
return Column(
spacing: 30,
children: [
Expanded(
child: Container(
color: AppColor.blueNormal,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(),
ObxValue((data) {
final status = data.value.status;
if (status == ResourceStatus.loading) {
return Container(
width: 128.w,
height: 128.h,
child: Center(child: CupertinoActivityIndicator(color: AppColor.greenNormal)),
);
}
if (status == ResourceStatus.error) {
return Container(
width: 128.w,
height: 128.h,
child: Center(child: Text('خطا در دریافت اطلاعات')),
);
}
// Default UI
return Container(
width: 128.w,
height: 128.h,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.blueLightActive,
),
child: Center(
child: data.value.data?.image != null
? CircleAvatar(
radius: 64.w,
backgroundImage: NetworkImage(data.value.data!.image!),
)
: Icon(Icons.person, size: 64.w),
),
);
}, controller.userProfile),
],
),
),
),
Expanded(
flex: 3,
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
rolesWidget(),
SizedBox(height: 12.h),
ObxValue((data) {
if (data.value.status == ResourceStatus.loading) {
return LoadingWidget();
} else if (data.value.status == ResourceStatus.error) {
return ErrorWidget('خطا در دریافت اطلاعات کاربر');
} else if (data.value.status == ResourceStatus.success) {
return Column(
spacing: 6,
children: [
ObxValue((isOpen) {
return GestureDetector(
onTap: () => isOpen.toggle(),
child: AnimatedContainer(
height: isOpen.value ? 320.h : 47.h,
duration: Duration(milliseconds: 500),
curve: Curves.linear,
child: userProfileInformation(data.value),
),
);
}, controller.isUserInformationOpen),
Visibility(
visible:
data.value.data?.unitName != null ||
data.value.data?.unitAddress != null ||
data.value.data?.unitPostalCode != null ||
data.value.data?.unitRegistrationNumber != null ||
data.value.data?.unitEconomicalNumber != null ||
data.value.data?.unitCity != null ||
data.value.data?.unitProvince != null ||
data.value.data?.unitNationalId != null,
child: ObxValue((isOpen) {
return GestureDetector(
onTap: () => isOpen.toggle(),
child: AnimatedContainer(
height: isOpen.value ? 320.h : 47.h,
duration: Duration(milliseconds: 500),
curve: Curves.linear,
child: unitInformation(data.value),
),
);
}, controller.isUnitInformationOpen),
),
],
);
} else {
return SizedBox.shrink();
}
}, controller.userProfile),
GestureDetector(
onTap: () {
Get.bottomSheet(changePasswordBottomSheet(), isScrollControlled: true);
},
child: Container(
height: 47.h,
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 8.h),
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: const Color(0xFFD6D6D6)),
),
child: Row(
spacing: 6,
children: [
Assets.vec.lockSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
Text(
'تغییر رمز عبور',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
],
),
),
),
GestureDetector(
onTap: () {
Get.bottomSheet(exitBottomSheet(), isScrollControlled: true);
},
child: Container(
height: 47.h,
margin: EdgeInsets.symmetric(horizontal: 8),
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: const Color(0xFFD6D6D6)),
),
child: Row(
spacing: 6,
children: [
Assets.vec.logoutSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.redNormal, BlendMode.srcIn),
),
Text(
'خروج',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.redNormal),
),
],
),
),
),
SizedBox(height: 100),
],
),
),
),
],
);
}
Container invoiceIssuanceInformation() => Container();
Widget bankInformationWidget() => Column(
spacing: 16,
children: [
itemList(title: 'نام بانک', content: 'سامان'),
itemList(title: 'نام صاحب حساب', content: 'رضا رضایی'),
itemList(title: 'شماره کارت ', content: '54154545415'),
itemList(title: 'شماره حساب', content: '62565263263652'),
itemList(title: 'شماره شبا', content: '62565263263652'),
],
);
Widget userProfileInformation(Resource<UserProfile> value) {
UserProfile item = value.data!;
return Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: ObxValue(
(val) => Container(
height: val.value ? 320.h : 47.h,
margin: EdgeInsets.symmetric(horizontal: 8, vertical: val.value ? 8 : 0),
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.5, color: AppColor.darkGreyLight),
),
child: val.value
? Column(
spacing: 6,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
Get.bottomSheet(
userInformationBottomSheet(),
isScrollControlled: true,
ignoreSafeArea: false,
);
},
child: Assets.vec.editSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
child: Column(
children: [
itemList(
title: 'نام و نام خانوادگی',
content: item.fullname ?? 'نامشخص',
icon: Assets.vec.userSvg.path,
hasColoredBox: true,
),
itemList(
title: 'کدملی',
content: item.nationalId ?? 'نامشخص',
icon: Assets.vec.tagUserSvg.path,
),
itemList(
title: 'موبایل',
content: item.mobile ?? 'نامشخص',
icon: Assets.vec.callSvg.path,
),
itemList(
title: 'شماره شناسنامه',
content: item.nationalCode ?? 'نامشخص',
icon: Assets.vec.userSquareSvg.path,
),
itemList(
title: 'تاریخ تولد',
content: item.birthday?.toJalali.formatCompactDate() ?? 'نامشخص',
icon: Assets.vec.calendarSvg.path,
),
//todo
itemList(
title: 'استان',
content: item.province ?? 'نامشخص',
icon: Assets.vec.pictureFrameSvg.path,
),
itemList(
title: 'شهر',
content: item.city ?? 'نامشخص',
icon: Assets.vec.mapSvg.path,
),
],
),
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [Icon(CupertinoIcons.chevron_down, color: AppColor.iconColor)],
),
),
controller.isUserInformationOpen,
),
),
ObxValue(
(isOpen) => AnimatedPositioned(
right: 16,
top: isOpen.value ? -7 : 11,
duration: Duration(milliseconds: 500),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: isOpen.value
? BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.5, color: Color(0xFFA9A9A9)),
)
: null,
child: Text(
'اطلاعات هویتی',
style: AppFonts.yekan16.copyWith(color: AppColor.iconColor),
),
),
),
controller.isUserInformationOpen,
),
],
);
}
Widget unitInformation(Resource<UserProfile> value) {
UserProfile item = value.data!;
return Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: ObxValue(
(val) => Container(
height: val.value ? 320.h : 47.h,
margin: EdgeInsets.symmetric(horizontal: 8, vertical: val.value ? 12 : 0),
padding: EdgeInsets.symmetric(horizontal: 11.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.5, color: AppColor.darkGreyLight),
),
child: val.value
? Column(
children: [
SizedBox(height: 5.h),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
Get.bottomSheet(
userInformationBottomSheet(),
isScrollControlled: true,
ignoreSafeArea: false,
);
},
child: Assets.vec.editSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
child: Column(
spacing: 2,
children: [
itemList(
title: 'نام صنفی',
content: item.unitName ?? 'نامشخص',
hasColoredBox: true,
visible: item.unitName != null,
),
itemList(
title: 'شناسنامه ملی',
content: item.unitNationalId ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'شماره ثبت',
content: item.unitRegistrationNumber ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'کد اقتصادی',
content: item.unitEconomicalNumber ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'کد پستی',
content: item.unitPostalCode ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'استان',
content: item.province ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'شهر',
content: item.city ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(title: 'آدرس', content: item.unitAddress ?? 'نامشخص'),
],
),
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [Icon(CupertinoIcons.chevron_down, color: AppColor.iconColor)],
),
),
controller.isUnitInformationOpen,
),
),
ObxValue(
(isOpen) => AnimatedPositioned(
right: 16,
top: isOpen.value ? -2 : 11,
duration: Duration(milliseconds: 500),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: isOpen.value
? BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.5, color: Color(0xFFA9A9A9)),
)
: null,
child: Text(
'اطلاعات صنفی',
style: AppFonts.yekan16.copyWith(color: AppColor.iconColor),
),
),
),
controller.isUnitInformationOpen,
),
],
);
}
Widget itemList({
required String title,
required String content,
String? icon,
bool hasColoredBox = false,
bool? visible,
}) => Visibility(
visible: visible ?? true,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12.h, vertical: 6.h),
decoration: BoxDecoration(
color: hasColoredBox ? AppColor.greenLight : Colors.transparent,
borderRadius: BorderRadius.circular(8),
border: hasColoredBox
? Border.all(width: 0.25, color: AppColor.bgDark)
: Border.all(width: 0, color: Colors.transparent),
),
child: Row(
spacing: 4,
children: [
if (icon != null)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: SvgGenImage.vec(icon).svg(
width: 20.w,
height: 20.h,
colorFilter: ColorFilter.mode(AppColor.textColor, BlendMode.srcIn),
),
),
Text(title, style: AppFonts.yekan14.copyWith(color: AppColor.textColor)),
Spacer(),
Text(content, style: AppFonts.yekan14.copyWith(color: AppColor.textColor)),
],
),
),
);
Widget cardActionWidget({
required String title,
required VoidCallback onPressed,
required String icon,
bool selected = false,
ColorFilter? color,
Color? cardColor,
Color? cardIconColor,
Color? textColor,
}) {
return GestureDetector(
onTap: onPressed,
child: Column(
spacing: 4,
children: [
Container(
width: 52.w,
height: 52.h,
padding: EdgeInsets.all(6),
decoration: ShapeDecoration(
color: cardColor ?? AppColor.blueLight,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: cardIconColor,
borderRadius: BorderRadius.circular(8),
),
child: SvgGenImage.vec(icon).svg(
width: 40.w,
height: 40.h,
colorFilter: color ?? ColorFilter.mode(Colors.white, BlendMode.srcIn),
),
),
),
SizedBox(height: 2),
Text(
title,
style: AppFonts.yekan10.copyWith(color: AppColor.textColor),
textAlign: TextAlign.center,
),
],
),
);
}
Widget userInformationBottomSheet() {
return BaseBottomSheet(
height: 750.h,
child: SingleChildScrollView(
child: Column(
spacing: 8,
children: [
Text(
'ویرایش اطلاعات هویتی',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.darkGreyDarkHover),
),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 12,
children: [
RTextField(
controller: controller.nameController,
label: 'نام',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
RTextField(
controller: controller.lastNameController,
label: 'نام خانوادگی',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
RTextField(
controller: controller.nationalCodeController,
label: 'شماره شناسنامه',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
RTextField(
controller: controller.nationalIdController,
label: 'کد ملی',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
ObxValue((data) {
return RTextField(
controller: controller.birthdayController,
label: 'تاریخ تولد',
initText: data.value?.formatCompactDate() ?? '',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
onTap: () {},
);
}, controller.birthDate),
SizedBox(),
],
),
),
SizedBox(),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 8,
children: [
Text(
'عکس پروفایل',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
ObxValue((data) {
return Container(
width: Get.width,
height: 270,
decoration: BoxDecoration(
color: AppColor.lightGreyNormal,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: AppColor.blackLight),
),
child: Center(
child: data.value == null
? Padding(
padding: const EdgeInsets.fromLTRB(30, 10, 10, 30),
child: Image.network(
controller.userProfile.value.data?.image ?? '',
),
)
: Image.file(File(data.value!.path), fit: BoxFit.cover),
),
);
}, controller.selectedImage),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RElevated(
text: 'گالری',
width: 150.w,
height: 40.h,
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
onPressed: () async {
controller.selectedImage.value = await controller.imagePicker.pickImage(
source: ImageSource.gallery,
imageQuality: 60,
maxWidth: 1080,
maxHeight: 720,
);
},
),
SizedBox(width: 16),
ROutlinedElevated(
text: 'دوربین',
width: 150.w,
height: 40.h,
textStyle: AppFonts.yekan20.copyWith(color: AppColor.blueNormal),
onPressed: () async {
controller.selectedImage.value = await controller.imagePicker.pickImage(
source: ImageSource.camera,
imageQuality: 60,
maxWidth: 1080,
maxHeight: 720,
);
},
),
],
),
],
),
),
Row(
spacing: 16,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ObxValue((data) {
return RElevated(
height: 40.h,
text: 'ویرایش',
isLoading: data.value,
onPressed: () async {
await controller.updateUserProfile();
controller.getUserProfile();
Get.back();
},
);
}, controller.isOnLoading),
ROutlinedElevated(
height: 40.h,
text: 'انصراف',
borderColor: AppColor.blueNormal,
onPressed: () {
Get.back();
},
),
],
),
],
),
),
);
}
Widget changePasswordBottomSheet() {
return BaseBottomSheet(
height: 400.h,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
child: Column(
spacing: 8,
children: [
Text(
'تغییر رمز عبور',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.darkGreyDarkHover),
),
SizedBox(),
RTextField(
controller: controller.oldPasswordController,
hintText: 'رمز عبور قبلی',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'رمز عبور را وارد کنید';
} else if (controller.userProfile.value.data?.password != value) {
return 'رمز عبور صحیح نیست';
}
return null;
},
),
RTextField(
controller: controller.newPasswordController,
hintText: 'رمز عبور جدید',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'رمز عبور را وارد کنید';
} else if (value.length < 6) {
return 'رمز عبور باید بیش از 6 کارکتر باشد.';
}
return null;
},
),
RTextField(
controller: controller.retryNewPasswordController,
hintText: 'تکرار رمز عبور جدید',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'رمز عبور را وارد کنید';
} else if (value.length < 6) {
return 'رمز عبور باید بیش از 6 کارکتر باشد.';
} else if (controller.newPasswordController.text != value) {
return 'رمز عبور جدید یکسان نیست';
}
return null;
},
),
SizedBox(),
Row(
spacing: 16,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RElevated(
height: 40.h,
text: 'ویرایش',
onPressed: () async {
if (controller.formKey.currentState?.validate() != true) {
return;
}
await controller.updatePassword();
controller.getUserProfile();
controller.clearPasswordForm();
Get.back();
},
),
ROutlinedElevated(
height: 40.h,
text: 'انصراف',
borderColor: AppColor.blueNormal,
onPressed: () {
Get.back();
},
),
],
),
],
),
),
),
);
}
Widget exitBottomSheet() {
return BaseBottomSheet(
height: 220.h,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
child: Column(
spacing: 8,
children: [
Text('خروج', style: AppFonts.yekan16Bold.copyWith(color: AppColor.error)),
SizedBox(),
Text(
'آیا مطمئن هستید که می‌خواهید از حساب کاربری خود خارج شوید؟',
textAlign: TextAlign.center,
style: AppFonts.yekan16Bold.copyWith(color: AppColor.textColor),
),
SizedBox(),
Row(
spacing: 16,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RElevated(
height: 40.h,
text: 'خروج',
backgroundColor: AppColor.error,
onPressed: () async {
await Future.wait([
controller.tokenService.deleteModuleTokens(Module.chicken),
controller.gService.clearSelectedModule(),
]).then((value) async {
await removeChickenDI();
Get.offAllNamed("/moduleList");
});
},
),
ROutlinedElevated(
height: 40.h,
text: 'انصراف',
borderColor: AppColor.blueNormal,
onPressed: () {
Get.back();
},
),
],
),
],
),
),
),
);
}
Widget rolesWidget() {
return ObxValue((data) {
if (data.value.status == ResourceStatus.loading) {
return CupertinoActivityIndicator();
} else if (data.value.status == ResourceStatus.error) {
return ErrorWidget('خطا در دریافت اطلاعات کاربر');
} else if (data.value.status == ResourceStatus.success) {
List<String>? item = data.value.data?.roles;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 8.w),
physics: BouncingScrollPhysics(),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8.w,
children: List.generate(item?.length ?? 0, (index) {
Map tmpRole = getFaUserRoleWithOnTap(item?[index]);
return CustomChip(
isSelected: controller.gService.getRoute(Module.chicken) == tmpRole.values.first,
title: tmpRole.keys.first,
index: index,
onTap: (int p1) {
controller.changeUserRole(tmpRole.values.first);
},
);
}),
),
);
} else {
return SizedBox.shrink();
}
}, controller.userLocal);
}
}

View File

@@ -0,0 +1,18 @@
import 'package:rasadyar_core/core.dart';
class RoleLogic extends GetxController {
TokenStorageService tokenService = Get.find<TokenStorageService>();
GService gService = Get.find<GService>();
RxList<String> roles = <String>[].obs;
@override
void onInit() {
super.onInit();
List<String> items = tokenService.getUserLocal(Module.chicken)!.roles ?? [];
if (items.isNotEmpty) {
roles.assignAll(items);
}
}
}

View File

@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/common/fa_user_role.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class RolePage extends GetView<RoleLogic> {
const RolePage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
isBase: true,
child: Column(
children: [
Assets.images.selectRole.image(height: 212.h, width: Get.width.w, fit: BoxFit.cover),
ObxValue((data) {
return Expanded(
child: GridView.builder(
physics: BouncingScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 12.h,
crossAxisSpacing: 12.w,
childAspectRatio: 2,
),
itemCount: data.length,
hitTestBehavior: HitTestBehavior.opaque,
itemBuilder: (BuildContext context, int index) {
Map role = getFaUserRoleWithOnTap(data[index]);
return roleCard(
title: role.keys.first,
onTap: () async {
try {
String route = role.values.first;
await controller.gService.saveRoute(Module.chicken, route);
await controller.gService.saveRole(Module.chicken, data[index]);
Get.offAllNamed(route);
} catch (e) {
eLog(
"احتمالا در\n ``getFaUserRoleWithOnTap`` \nروت اش را تعریف نکردی 👻👻 ==>$e ",
);
}
},
);
},
),
);
}, controller.roles),
],
),
);
}
}
Widget roleCard({required String title, Function()? onTap, int? width, int? height}) {
return Container(
width: width?.w ?? 128.w,
height: height?.h ?? 48.h,
margin: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: AppColor.blueNormal, width: 1.w),
),
child: InkWell(
onTap: onTap,
child: Center(
child: Text(
title,
style: AppFonts.yekan12Bold.copyWith(color: AppColor.blueNormal),
textAlign: TextAlign.center,
),
),
),
);
}

View File

@@ -0,0 +1,34 @@
import 'package:rasadyar_chicken/features/common/presentation/page/auth/logic.dart';
import 'package:rasadyar_chicken/features/common/presentation/page/auth/view.dart';
import 'package:rasadyar_chicken/features/common/presentation/page/profile/logic.dart';
import 'package:rasadyar_chicken/features/common/presentation/page/profile/view.dart';
import 'package:rasadyar_chicken/features/common/presentation/page/role/logic.dart';
import 'package:rasadyar_chicken/features/common/presentation/page/role/view.dart';
import 'package:rasadyar_chicken/features/common/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
import 'package:rasadyar_chicken/presentation/widget/captcha/logic.dart';
import 'package:rasadyar_core/core.dart';
class CommonPages {
CommonPages._();
static List<GetPage> get pages => [
GetPage(
name: CommonRoutes.auth,
page: () => AuthPage(),
binding: BindingsBuilder(() {
Get.lazyPut(() => AuthLogic());
Get.lazyPut(() => CaptchaWidgetLogic());
Get.lazyPut(() => ChickenBaseLogic(), fenix: true);
}),
),
GetPage(
name: CommonRoutes.role,
page: () => RolePage(),
binding: BindingsBuilder(() {
Get.lazyPut(() => RoleLogic());
Get.lazyPut(() => ChickenBaseLogic(), fenix: true);
}),
),
];
}

View File

@@ -0,0 +1,8 @@
sealed class CommonRoutes {
CommonRoutes._();
static const auth = '/AuthChicken';
static const _base = '/chicken';
static const role = '$_base/role';
static const String profile = '$_base/profile';
}

Some files were not shown because too many files have changed in this diff Show More