258 lines
8.0 KiB
Dart
258 lines
8.0 KiB
Dart
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();
|
|
}
|
|
}
|