diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 5833be8..574cc9c 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -2,7 +2,7 @@ plugins { id("com.android.application") id("kotlin-android") id("dev.flutter.flutter-gradle-plugin") - // اضافه کردن پلاگin گوگل سرویسز برای فایربیس + // اضافه کردن پلاگین گوگل سرویسز برای فایربیس id("com.google.gms.google-services") } @@ -12,8 +12,7 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - // فلاتر به صورت پیش‌فرض از جاوا ۸ استفاده می‌کند. - // اگر به صورت دستی به ۱۱ تغییر داده‌اید، مشکلی نیست. + // استفاده از جاوا ۸ برای سازگاری بهتر sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } @@ -24,8 +23,6 @@ android { defaultConfig { applicationId = "com.example.lba" - // حداقل SDK برای کتابخانه‌های جدید فایربیس معمولاً ۲۱ است. - // ۲۴ که شما تنظیم کرده‌اید کاملاً مناسب است. minSdk = 24 targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode @@ -33,13 +30,17 @@ android { } buildTypes { - release { - signingConfig = signingConfigs.getByName("debug") - // این تنظیمات برای نسخه نهایی (release) مهم هستند - // اما برای تست می‌توانید آن‌ها را غیرفعال نگه دارید. - // isMinifyEnabled = true - // isShrinkResources = true - // proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + getByName("release") { + // برای نسخه نهایی (release) بهتر است از کلید امضای خودتان استفاده کنید. + // signingConfig = signingConfigs.getByName("release") + signingConfig = signingConfigs.getByName("debug") // موقتا برای تست + + // فعال‌سازی کوچک‌سازی و بهینه‌سازی کد با سینتکس کاتلین + isMinifyEnabled = true + isShrinkResources = true + + // افزودن فایل قوانین ProGuard برای جلوگیری از حذف کلاس‌های ضروری + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } } @@ -48,10 +49,8 @@ flutter { source = "../.." } -// اضافه کردن این بخش برای کتابخانه‌های فایربیس dependencies { // اضافه کردن Firebase Bill of Materials (BoM) - // این کار نسخه‌های تمام کتابخانه‌های فایربیس را مدیریت می‌کند implementation(platform("com.google.firebase:firebase-bom:33.1.0")) // کتابخانه‌های مورد نیاز برای آنالیتیکس و احراز هویت diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 29ffa97..6367509 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -1,42 +1,40 @@ -# Flutter related --keep class io.flutter.app.** { *; } --keep class io.flutter.plugin.** { *; } --keep class io.flutter.util.** { *; } --keep class io.flutter.view.** { *; } --keep class io.flutter.** { *; } --keep class io.flutter.plugins.** { *; } +#=============== Flutter Core =============== +# قوانین مربوط به موتور و پلاگین‌های اصلی فلاتر -keep class io.flutter.embedding.** { *; } +-keep class io.flutter.plugins.** { *; } +-keep class io.flutter.app.** { *; } +-keep class io.flutter.plugin.** { *; } +-keep class io.flutter.util.** { *; } +-keep class io.flutter.view.** { *; } -# Mobile Scanner --keep class com.google.mlkit.** { *; } +#=============== Google Play & Firebase =============== +# این قوانین برای سرویس‌های گوگل پلی و فایربیس ضروری هستند -keep class com.google.android.gms.** { *; } +-dontwarn com.google.android.gms.** +-keep class com.google.firebase.** { *; } +-dontwarn com.google.firebase.** +-keep class com.google.android.play.core.** { *; } +-dontwarn com.google.android.play.core.** -# Geolocator +#=============== Mobile Scanner & ML Kit =============== +# قوانین مربوط به پکیج اسکنر کد QR و ML Kit +-keep class com.google.mlkit.** { *; } +-dontwarn com.google.mlkit.** + +#=============== Flutter Plugins =============== +# قوانین مربوط به سایر پکیج‌های استفاده شده -keep class com.baseflow.geolocator.** { *; } - -# Image Picker -keep class io.flutter.plugins.imagepicker.** { *; } - -# Permission Handler -keep class com.baseflow.permissionhandler.** { *; } -# Keep native methods +#=============== General Rules =============== +# قوانین عمومی برای حفظ متدهای نیتیو، کلاس‌های Parcelable و انوتیشن‌ها -keepclasseswithmembernames class * { native ; } -# Keep Parcelable implementations -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } -# General warnings --dontwarn com.google.android.gms.** --dontwarn com.google.mlkit.** --dontwarn java.lang.invoke.** - -# Keep annotations --keepattributes *Annotation* --keepattributes Signature --keepattributes InnerClasses --keepattributes EnclosingMethod +-keepattributes *Annotation*, Signature, InnerClasses, EnclosingMethod \ No newline at end of file diff --git a/assets/icons/brush.svg b/assets/icons/brush.svg new file mode 100644 index 0000000..ca6c6f5 --- /dev/null +++ b/assets/icons/brush.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/icons/edit prof.svg b/assets/icons/edit prof.svg new file mode 100644 index 0000000..a2cce7f --- /dev/null +++ b/assets/icons/edit prof.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/empty-wallet.svg b/assets/icons/empty-wallet.svg new file mode 100644 index 0000000..3ee2ec8 --- /dev/null +++ b/assets/icons/empty-wallet.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/icons/gift.svg b/assets/icons/gift.svg new file mode 100644 index 0000000..52dc741 --- /dev/null +++ b/assets/icons/gift.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/global-search.svg b/assets/icons/global-search.svg new file mode 100644 index 0000000..61da037 --- /dev/null +++ b/assets/icons/global-search.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/icons/global-search2.svg b/assets/icons/global-search2.svg new file mode 100644 index 0000000..53bd290 --- /dev/null +++ b/assets/icons/global-search2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/icons/heart.svg b/assets/icons/heart.svg new file mode 100644 index 0000000..2dd9197 --- /dev/null +++ b/assets/icons/heart.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/language-square.svg b/assets/icons/language-square.svg new file mode 100644 index 0000000..4ae8f37 --- /dev/null +++ b/assets/icons/language-square.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/logout.svg b/assets/icons/logout.svg new file mode 100644 index 0000000..c0c63b5 --- /dev/null +++ b/assets/icons/logout.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/icons/message-question.svg b/assets/icons/message-question.svg new file mode 100644 index 0000000..56d84db --- /dev/null +++ b/assets/icons/message-question.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/icons/notification.svg b/assets/icons/notification.svg new file mode 100644 index 0000000..2c19f5b --- /dev/null +++ b/assets/icons/notification.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/icons/shield.svg b/assets/icons/shield.svg new file mode 100644 index 0000000..ca018f8 --- /dev/null +++ b/assets/icons/shield.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index 0ed776d..2ebf61b 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -78,6 +78,9 @@ class $AssetsIconsGen { /// File path: assets/icons/back.svg SvgGenImage get back => const SvgGenImage('assets/icons/back.svg'); + /// File path: assets/icons/brush.svg + SvgGenImage get brush => const SvgGenImage('assets/icons/brush.svg'); + /// File path: assets/icons/calendar-tick 2.svg SvgGenImage get calendarTick2 => const SvgGenImage('assets/icons/calendar-tick 2.svg'); @@ -128,10 +131,17 @@ class $AssetsIconsGen { /// File path: assets/icons/down.svg SvgGenImage get down => const SvgGenImage('assets/icons/down.svg'); + /// File path: assets/icons/edit prof.svg + SvgGenImage get editProf => const SvgGenImage('assets/icons/edit prof.svg'); + /// File path: assets/icons/element-equal.svg SvgGenImage get elementEqual => const SvgGenImage('assets/icons/element-equal.svg'); + /// File path: assets/icons/empty-wallet.svg + SvgGenImage get emptyWallet => + const SvgGenImage('assets/icons/empty-wallet.svg'); + /// File path: assets/icons/favorite.svg SvgGenImage get favorite => const SvgGenImage('assets/icons/favorite.svg'); @@ -161,14 +171,28 @@ class $AssetsIconsGen { /// File path: assets/icons/game.svg SvgGenImage get game => const SvgGenImage('assets/icons/game.svg'); + /// File path: assets/icons/gift.svg + SvgGenImage get gift => const SvgGenImage('assets/icons/gift.svg'); + /// File path: assets/icons/girl_clothes.svg SvgGenImage get girlClothes => const SvgGenImage('assets/icons/girl_clothes.svg'); + /// File path: assets/icons/global-search.svg + SvgGenImage get globalSearch => + const SvgGenImage('assets/icons/global-search.svg'); + + /// File path: assets/icons/global-search2.svg + SvgGenImage get globalSearch2 => + const SvgGenImage('assets/icons/global-search2.svg'); + /// File path: assets/icons/healthicons_fruits-outline.svg SvgGenImage get healthiconsFruitsOutline => const SvgGenImage('assets/icons/healthicons_fruits-outline.svg'); + /// File path: assets/icons/heart.svg + SvgGenImage get heart => const SvgGenImage('assets/icons/heart.svg'); + /// File path: assets/icons/hugeicons_baby-boy-dress.svg SvgGenImage get hugeiconsBabyBoyDress => const SvgGenImage('assets/icons/hugeicons_baby-boy-dress.svg'); @@ -188,6 +212,10 @@ class $AssetsIconsGen { SvgGenImage get ionFastFoodOutline => const SvgGenImage('assets/icons/ion_fast-food-outline.svg'); + /// File path: assets/icons/language-square.svg + SvgGenImage get languageSquare => + const SvgGenImage('assets/icons/language-square.svg'); + /// File path: assets/icons/like.svg SvgGenImage get like => const SvgGenImage('assets/icons/like.svg'); @@ -200,6 +228,9 @@ class $AssetsIconsGen { /// File path: assets/icons/location.svg SvgGenImage get location => const SvgGenImage('assets/icons/location.svg'); + /// File path: assets/icons/logout.svg + SvgGenImage get logout => const SvgGenImage('assets/icons/logout.svg'); + /// File path: assets/icons/map selected.svg SvgGenImage get mapSelected => const SvgGenImage('assets/icons/map selected.svg'); @@ -235,6 +266,10 @@ class $AssetsIconsGen { SvgGenImage get materialSymbolsLocationWork => const SvgGenImage('assets/icons/material-symbols_location-work.svg'); + /// File path: assets/icons/message-question.svg + SvgGenImage get messageQuestion => + const SvgGenImage('assets/icons/message-question.svg'); + /// File path: assets/icons/microphone-2.svg SvgGenImage get microphone2 => const SvgGenImage('assets/icons/microphone-2.svg'); @@ -252,6 +287,10 @@ class $AssetsIconsGen { SvgGenImage get notificationBing => const SvgGenImage('assets/icons/notification-bing.svg'); + /// File path: assets/icons/notification.svg + SvgGenImage get notification => + const SvgGenImage('assets/icons/notification.svg'); + /// File path: assets/icons/ph_cheese.svg SvgGenImage get phCheese => const SvgGenImage('assets/icons/ph_cheese.svg'); @@ -296,6 +335,9 @@ class $AssetsIconsGen { SvgGenImage get selectedList => const SvgGenImage('assets/icons/selected list.svg'); + /// File path: assets/icons/shield.svg + SvgGenImage get shield => const SvgGenImage('assets/icons/shield.svg'); + /// File path: assets/icons/shopping-cart.svg SvgGenImage get shoppingCart => const SvgGenImage('assets/icons/shopping-cart.svg'); @@ -367,6 +409,7 @@ class $AssetsIconsGen { arrowRight, arrowUp, back, + brush, calendarTick2, calendarTick, camera2, @@ -382,7 +425,9 @@ class $AssetsIconsGen { deliveryOn, dislike, down, + editProf, elementEqual, + emptyWallet, favorite, flatColorIconsIdea, flatColorIconsPlanner, @@ -391,17 +436,23 @@ class $AssetsIconsGen { game2, gameIconsWinterGloves, game, + gift, girlClothes, + globalSearch, + globalSearch2, healthiconsFruitsOutline, + heart, hugeiconsBabyBoyDress, hugeiconsCheeseCake01, icRoundLocalOffer, infoPic, ionFastFoodOutline, + languageSquare, like, link2, list, location, + logout, mapSelected, map, materialSymbolsLocationAir, @@ -411,11 +462,13 @@ class $AssetsIconsGen { materialSymbolsLocationOn, materialSymbolsLocationOnn, materialSymbolsLocationWork, + messageQuestion, microphone2, nearby, nearby2, next, notificationBing, + notification, phCheese, phQrCode, pickUpOff, @@ -429,6 +482,7 @@ class $AssetsIconsGen { routing2, routing, selectedList, + shield, shoppingCart, slide2, slide3, diff --git a/lib/res/colors.dart b/lib/res/colors.dart index 5e5f869..7821f86 100644 --- a/lib/res/colors.dart +++ b/lib/res/colors.dart @@ -25,4 +25,5 @@ class LightAppColors{ static const textPrice = Color.fromARGB(255, 85, 84, 81); static const deliverySelectedButton = Color.fromARGB(255, 237, 247, 238); static const loadingBorder = Color.fromARGB(255, 239, 239, 239); + static const profileField = Color.fromARGB(255, 252, 252, 252); } \ No newline at end of file diff --git a/lib/screens/mains/discover/discover.dart b/lib/screens/mains/discover/discover.dart index 3a719a0..60e1171 100644 --- a/lib/screens/mains/discover/discover.dart +++ b/lib/screens/mains/discover/discover.dart @@ -5,7 +5,6 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:dots_indicator/dots_indicator.dart'; import 'package:lba/gen/assets.gen.dart'; import 'package:lba/res/colors.dart'; -import 'package:lba/widgets/customBottomSheet.dart'; import 'package:lba/widgets/remainingTime.dart'; import 'package:lba/widgets/search_bar.dart'; diff --git a/lib/screens/mains/nearby/bestNearby.dart b/lib/screens/mains/nearby/bestNearby.dart index e176294..21837fc 100644 --- a/lib/screens/mains/nearby/bestNearby.dart +++ b/lib/screens/mains/nearby/bestNearby.dart @@ -25,7 +25,6 @@ class _BestnearbyState extends State duration: const Duration(milliseconds: 1500), ); - // --- انیمیشن‌های مرحله‌ای برای هر بخش --- _staggeredAnimations = List.generate(3, (index) { return Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( @@ -48,7 +47,6 @@ class _BestnearbyState extends State super.dispose(); } - // --- ویجت انیمیشنی برای هر بخش --- Widget _buildAnimatedSection(Widget child, int index) { return FadeTransition( opacity: _staggeredAnimations[index], diff --git a/lib/screens/mains/profile/profile.dart b/lib/screens/mains/profile/profile.dart index 21872e4..16ac27d 100644 --- a/lib/screens/mains/profile/profile.dart +++ b/lib/screens/mains/profile/profile.dart @@ -1,10 +1,444 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:lba/gen/assets.gen.dart'; +import 'package:lba/res/colors.dart'; -class Profile extends StatelessWidget { +class Profile extends StatefulWidget { const Profile({super.key}); + @override + State createState() => _ProfileState(); +} + +class _ProfileState extends State with TickerProviderStateMixin { + bool _isDarkMode = false; + late AnimationController _animationController; + late List> _animations; + + @override + void initState() { + super.initState(); + + _animationController = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 1200), + ); + + const int itemCount = 12; + _animations = List.generate(itemCount, (index) { + final double startTime = (index / itemCount) * 0.6; + final double endTime = (startTime + 0.4).clamp(0.0, 1.0); + + return Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + startTime, + endTime, + curve: Curves.easeOutCubic, + ), + ), + ); + }); + + _animationController.forward(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + Widget _buildAnimatedWidget(Widget child, int index) { + if (index >= _animations.length) return child; + + final slideAnimation = Tween( + begin: const Offset(0.0, 0.5), + end: Offset.zero, + ).animate(_animations[index]); + + return FadeTransition( + opacity: _animations[index], + child: SlideTransition( + position: slideAnimation, + child: child, + ), + ); + } + @override Widget build(BuildContext context) { - return const Placeholder(); + return Scaffold( + backgroundColor: Colors.white, + appBar: PreferredSize( + preferredSize: const Size.fromHeight(kToolbarHeight + 1), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(18), + bottomRight: Radius.circular(18), + ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: AppBar( + surfaceTintColor: Colors.white, + backgroundColor: Colors.transparent, + elevation: 0, + centerTitle: true, + title: const Text( + 'Profile', + style: TextStyle( + color: Colors.black, + fontSize: 17, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildAnimatedWidget(_SectionTitle(title: 'General'), 0), + _buildAnimatedWidget( + _buildSectionContainer( + child: Column( + children: [ + _buildInfoTile( + icon: SvgPicture.asset(Assets.icons.globalSearch2.path, width: 22), + title: 'Country', + trailing: const Text( + 'United Arab Emirates', + style: TextStyle( + color: LightAppColors.primary, + fontSize: 15, + fontWeight: FontWeight.w500), + ), + ), + _buildInfoTile( + icon: SvgPicture.asset(Assets.icons.languageSquare.path, width: 22), + title: 'Language', + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.asset(Assets.images.usa.path, width: 24), + const SizedBox(width: 8), + const Text('English', + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.black)), + const SizedBox(width: 8), + SvgPicture.asset(Assets.icons.arrowRight.path, color: Colors.black) + ], + ), + ), + _buildSwitchTile( + icon: SvgPicture.asset(Assets.icons.brush.path, width: 22), + title: 'Dark mode', + value: _isDarkMode, + onChanged: (value) => setState(() => _isDarkMode = value), + ), + ], + ), + ), + 1, + ), + const SizedBox(height: 8), + _buildAnimatedWidget( + PressableListItem( + child: _buildDecoratedNavigationTile( + icon: SvgPicture.asset(Assets.icons.editProf.path, width: 22), + title: 'Edit Profile'), + ), + 2), + const SizedBox(height: 8), + _buildAnimatedWidget( + PressableListItem( + child: _buildDecoratedNavigationTile( + icon: SvgPicture.asset(Assets.icons.notification.path, color: LightAppColors.primary, width: 22), + title: 'Notifications'), + ), + 3), + const SizedBox(height: 8), + _buildAnimatedWidget( + PressableListItem( + child: _buildDecoratedNavigationTile( + icon: SvgPicture.asset(Assets.icons.emptyWallet.path, width: 22), + title: 'Transactions & Wallets'), + ), + 4), + const SizedBox(height: 8), + _buildAnimatedWidget( + PressableListItem( + child: _buildDecoratedNavigationTile( + icon: SvgPicture.asset(Assets.icons.gift.path, width: 22), + title: 'Exclusive Perks'), + ), + 5), + const SizedBox(height: 8), + _buildAnimatedWidget( + PressableListItem( + child: _buildDecoratedNavigationTile( + icon: SvgPicture.asset(Assets.icons.cardPos.path, color: LightAppColors.primary, width: 22), + title: 'Payment methods'), + ), + 6), + const SizedBox(height: 8), + _buildAnimatedWidget( + PressableListItem( + child: _buildDecoratedNavigationTile( + icon: SvgPicture.asset(Assets.icons.heart.path, width: 22), + title: 'Favorite Stores'), + ), + 7), + const SizedBox(height: 24), + _buildAnimatedWidget(_SectionTitle(title: 'Preferences'), 8), + _buildAnimatedWidget( + PressableListItem( + child: _buildDecoratedNavigationTile( + icon: SvgPicture.asset(Assets.icons.shield.path, width: 22), + title: 'Legal & Policies'), + ), + 9), + const SizedBox(height: 8), + _buildAnimatedWidget( + PressableListItem( + child: _buildDecoratedNavigationTile( + icon: SvgPicture.asset(Assets.icons.messageQuestion.path, width: 22), + title: 'Help & Support'), + ), + 10), + const SizedBox(height: 8), + _buildAnimatedWidget(PressableListItem(child: _buildLogoutButton()), 11), + const SizedBox(height: 85), + ], + ), + ), + ), + ); + } + + Widget _buildSectionContainer({required Widget child}) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: child, + ); + } + + Widget _buildInfoTile( + {required Widget icon, required String title, required Widget trailing}) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + icon, + const SizedBox(width: 16), + Expanded( + child: Text(title, + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.w500, color: Colors.black))), + trailing, + ], + ), + ); + } + + Widget _buildSwitchTile( + {required Widget icon, + required String title, + required bool value, + required ValueChanged onChanged}) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2.0), + child: Row( + children: [ + icon, + const SizedBox(width: 16), + Expanded( + child: Text(title, + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.w500))), + Transform.scale( + scale: 0.75, + child: Switch( + value: value, + onChanged: onChanged, + activeColor: const Color(0xFF34C759), + activeTrackColor: const Color(0xFF34C759).withOpacity(0.5), + inactiveThumbColor: Colors.white, + inactiveTrackColor: const Color.fromARGB(57, 141, 141, 141), + ), + ), + ], + ), + ); + } + + Widget _buildDecoratedNavigationTile( + {required Widget icon, required String title}) { + return Container( + decoration: BoxDecoration( + color: LightAppColors.profileField, + borderRadius: BorderRadius.circular(14), + border: Border.all(color: LightAppColors.divider, width: 0.5), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 17), + child: Row( + children: [ + icon, + const SizedBox(width: 16), + Expanded( + child: Text(title, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.black))), + SvgPicture.asset(Assets.icons.arrowRight.path, color: Colors.black) + ], + ), + ), + ); + } + + Widget _buildLogoutButton() { + return Container( + decoration: BoxDecoration( + color: LightAppColors.profileField, + borderRadius: BorderRadius.circular(14), + border: Border.all(color: LightAppColors.divider, width: 0.5), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + child: Row( + children: [ + SvgPicture.asset( + Assets.icons.logout.path, + width: 22, + ), + const SizedBox(width: 16), + const Expanded( + child: Text( + 'Logout', + style: TextStyle( + color: LightAppColors.allReviewOpener, + fontSize: 16, + fontWeight: FontWeight.w500), + ), + ), + ], + ), + ), + ); + } +} + +// ویجت برای افکت لمس +class PressableListItem extends StatefulWidget { + final Widget child; + const PressableListItem({super.key, required this.child}); + + @override + State createState() => _PressableListItemState(); +} + +class _PressableListItemState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 150), + reverseDuration: const Duration(milliseconds: 300), + ); + _scaleAnimation = Tween(begin: 1.0, end: 0.97).animate( + CurvedAnimation(parent: _controller, curve: Curves.easeOut), + ); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + void _onTapDown(TapDownDetails details) { + _controller.forward(); + } + + void _onTapUp(TapUpDetails details) { + Future.delayed(const Duration(milliseconds: 100), () { + if(mounted) { + _controller.reverse(); + } + }); + } + + void _onTapCancel() { + _controller.reverse(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: _onTapDown, + onTapUp: _onTapUp, + onTapCancel: _onTapCancel, + onTap: () {}, + child: ScaleTransition( + scale: _scaleAnimation, + child: widget.child, + ), + ); + } +} + +class _SectionTitle extends StatelessWidget { + final String title; + const _SectionTitle({required this.title}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: 12.0, top: 8.0, left: 12.0), + child: Text( + title, + style: const TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ); } } \ No newline at end of file diff --git a/lib/widgets/animated_splash_screen.dart b/lib/widgets/animated_splash_screen.dart index 4dbb50c..cc02999 100644 --- a/lib/widgets/animated_splash_screen.dart +++ b/lib/widgets/animated_splash_screen.dart @@ -30,7 +30,7 @@ class _CoolSplashScreenState extends State super.initState(); _mainController = AnimationController( - duration: const Duration(milliseconds: 4000), + duration: const Duration(milliseconds: 4000), vsync: this, ); @@ -97,8 +97,16 @@ class _CoolSplashScreenState extends State begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ - Color.lerp(const Color(0xFFF5F5F5), const Color(0xFFE0E0E0), _backgroundAnimation.value)!, - Color.lerp(const Color(0xFFFFFFFF), const Color(0xFFF5F5F5), _backgroundAnimation.value)!, + Color.lerp( + const Color(0xFFF5F5F5), + const Color(0xFFE0E0E0), + _backgroundAnimation.value, + )!, + Color.lerp( + const Color(0xFFFFFFFF), + const Color(0xFFF5F5F5), + _backgroundAnimation.value, + )!, ], ), ), @@ -108,13 +116,16 @@ class _CoolSplashScreenState extends State Particle( animation: _particlesAnimation, size: Random().nextDouble() * 5 + 2, - color: Colors.blueGrey.withOpacity(Random().nextDouble() * 0.3 + 0.1), + color: Colors.blueGrey.withOpacity( + Random().nextDouble() * 0.3 + 0.1, + ), alignment: Alignment( - (Random().nextDouble() * 2 - 1) * (2 - _particlesAnimation.value), - (Random().nextDouble() * 2 - 1) * (2 - _particlesAnimation.value), + (Random().nextDouble() * 2 - 1) * + (2 - _particlesAnimation.value), + (Random().nextDouble() * 2 - 1) * + (2 - _particlesAnimation.value), ), ), - Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -163,12 +174,9 @@ class Particle extends StatelessWidget { child: Container( width: size, height: size, - decoration: BoxDecoration( - color: color, - shape: BoxShape.circle, - ), + decoration: BoxDecoration(color: color, shape: BoxShape.circle), ), ), ); } -} \ No newline at end of file +}