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(); GService gService = Get.find(); TokenStorageService tokenService = Get.find(); RxInt selectedInformationType = 0.obs; Rxn birthDate = Rxn(); Rx> userProfile = Rx>( Resource.loading(), ); Rx> userLocal = Rx>( 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 cites = [].obs; Rxn selectedProvince = Rxn(); Rxn selectedCity = Rxn(); GlobalKey formKey = GlobalKey(); ImagePicker imagePicker = ImagePicker(); Rxn selectedImage = Rxn(); 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 getUserProfile() async { userProfile.value = Resource.loading(); await safeCall( call: () async => await commonRepository.getUserProfile( token: tokenService.accessToken.value!, ), onSuccess: (result) { if (result != null) { userProfile.value = Resource.success(result); } }, onError: (error, stackTrace) {}, ); } Future getCites() async { await safeCall( call: () => commonRepository.getCity( provinceName: selectedProvince.value?.name ?? '', ), onSuccess: (result) { if (result != null && result.isNotEmpty) { cites.value = result; } }, ); } Future 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 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 getUserRole() async { userLocal.value = Resource.loading(); await safeCall( 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 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(); } }