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 { 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 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 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? 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); } }