feat : image profile

This commit is contained in:
2025-07-21 16:05:49 +03:30
parent 99503a2d72
commit a0c1d452c6
3 changed files with 196 additions and 77 deletions

View File

@@ -28,6 +28,20 @@ class ProfileLogic extends GetxController {
Rxn<IranProvinceCityModel> selectedCity = Rxn();
GlobalKey<FormState> formKey = GlobalKey();
ImagePicker imagePicker = ImagePicker();
Rxn<XFile> selectedImage = Rxn<XFile>();
RxnString _base64Image = RxnString();
RxBool isOnLoading = false.obs;
@override
void onInit() {
super.onInit();
ever(selectedImage, (data) async {
if (data?.path != null) {
_base64Image.value = await convertImageToBase64(data!.path);
}
});
}
@override
void onReady() {
@@ -92,14 +106,22 @@ class ProfileLogic extends GetxController {
nationalCode: nationalCodeController.text,
nationalId: nationalIdController.text,
birthday: birthDate.value?.toGregorian().toString(),
image: _base64Image.value,
personType: 'self',
type: 'self_profile',
);
isOnLoading.value = true;
await safeCall(
call: () async => await rootLogic.chickenRepository.updateUserProfile(
token: rootLogic.tokenService.accessToken.value!,
userProfile: userProfile,
),
onSuccess: (result) {
isOnLoading.value = false;
},
onError: (error, stackTrace) {
isOnLoading.value = false;
},
);
}

View File

@@ -1,3 +1,6 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart';
import 'package:rasadyar_auth/presentation/routes/pages.dart';
@@ -25,21 +28,49 @@ class ProfilePage extends GetView<ProfileLogic> {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(),
Container(
width: 128.w,
height: 128.h,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.blueLightActive,
),
child: Center(
child: Assets.vec.userSvg.svg(
width: 64.w,
height: 64.h,
colorFilter: ColorFilter.mode(AppColor.whiteLight, BlendMode.srcIn),
),
),
),
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: CircleAvatar(
radius: 64.w,
backgroundImage:
NetworkImage(data.value.data!.image!)
),
),
);
},
controller.userProfile,
)
],
),
),
@@ -96,16 +127,17 @@ class ProfilePage extends GetView<ProfileLogic> {
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 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() {
return ObxValue((data) {
@@ -120,7 +152,8 @@ class ProfilePage extends GetView<ProfileLogic> {
children: [
buildRowOnTapped(
onTap: () {
Get.bottomSheet(userInformationBottomSheet(), isScrollControlled: true);
Get.bottomSheet(
userInformationBottomSheet(), isScrollControlled: true, ignoreSafeArea: false);
},
titleWidget: Column(
spacing: 3,
@@ -184,33 +217,34 @@ class ProfilePage extends GetView<ProfileLogic> {
required String content,
String? icon,
bool hasColoredBox = false,
}) => 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.mediumGreyNormalActive, BlendMode.srcIn),
),
),
Text(title, style: AppFonts.yekan12.copyWith(color: AppColor.mediumGreyNormalActive)),
Spacer(),
Text(content, style: AppFonts.yekan13.copyWith(color: AppColor.mediumGreyNormalHover)),
],
),
);
}) =>
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.mediumGreyNormalActive, BlendMode.srcIn),
),
),
Text(title, style: AppFonts.yekan12.copyWith(color: AppColor.mediumGreyNormalActive)),
Spacer(),
Text(content, style: AppFonts.yekan13.copyWith(color: AppColor.mediumGreyNormalHover)),
],
),
);
Widget cardActionWidget({
required String title,
@@ -238,7 +272,7 @@ class ProfilePage extends GetView<ProfileLogic> {
width: 40,
height: 40,
colorFilter:
color ??
color ??
ColorFilter.mode(
selected ? AppColor.blueNormal : AppColor.whiteLight,
BlendMode.srcIn,
@@ -260,7 +294,7 @@ class ProfilePage extends GetView<ProfileLogic> {
Widget userInformationBottomSheet() {
return BaseBottomSheet(
height: 500.h,
height: 750.h,
child: SingleChildScrollView(
child: Column(
spacing: 8,
@@ -270,16 +304,6 @@ class ProfilePage extends GetView<ProfileLogic> {
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: [_provinceWidget(), _cityWidget()]),
),*/
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
@@ -333,25 +357,75 @@ class ProfilePage extends GetView<ProfileLogic> {
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(
spacing: 16,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RElevated(
text: 'گالری',
width: 150.w,
height: 40.h,
text: 'ویرایش',
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
onPressed: () async {
await controller.updateUserProfile();
controller.getUserProfile();
Get.back();
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,
text: 'انصراف',
borderColor: AppColor.blueNormal,
onPressed: () {
Get.back();
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,
);
},
),
],
@@ -359,7 +433,32 @@ class ProfilePage extends GetView<ProfileLogic> {
],
),
),
SizedBox(),
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();
},
),
],
),
],
),
),

View File

@@ -35,8 +35,6 @@ class SalesOutOfProvinceLogic extends GetxController {
RxBool isLoadingMoreAllocationsMade = false.obs;
Rxn<IranProvinceCityModel> selectedCity = Rxn();
//TODO add this to Di
ImagePicker imagePicker = ImagePicker();
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController quarantineCodeController = TextEditingController();