proxybuy-flutter/lib/screens/mains/profile/profile.dart

577 lines
20 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/res/colors.dart';
import 'package:lba/screens/mains/profile/help_and_support_page.dart';
import 'package:lba/screens/mains/profile/notification_settings_page.dart';
import 'package:lba/screens/mains/profile/transactions_wallets_page.dart';
import 'package:lba/utils/theme_manager.dart';
import 'package:lba/widgets/country_popup.dart';
import 'package:lba/widgets/custom_switch_tile.dart';
import 'package:lba/widgets/language_selection_dialog.dart';
import 'package:lba/widgets/legal_and_policies_page.dart';
import 'package:lba/widgets/logout_popup.dart';
import 'package:lba/widgets/profile_app_bar.dart';
class Profile extends StatefulWidget {
const Profile({super.key});
@override
State<Profile> createState() => _ProfileState();
}
class _ProfileState extends State<Profile> with TickerProviderStateMixin {
late AnimationController _animationController;
late List<Animation<double>> _animations;
String _currentLanguage = '🇺🇲 English';
String _currentFlag = 'assets/icons/usa circle.svg';
final GlobalKey _languageTileKey = GlobalKey();
@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<double>(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();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_updateSystemUI();
}
void _updateSystemUI() {
final brightness = Theme.of(context).brightness;
final isDark = brightness == Brightness.dark;
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: isDark ? Brightness.light : Brightness.dark,
statusBarBrightness: isDark ? Brightness.dark : Brightness.light,
systemNavigationBarColor: AppColors.scaffoldBackground,
systemNavigationBarIconBrightness: isDark ? Brightness.light : Brightness.dark,
systemNavigationBarDividerColor: AppColors.divider,
),
);
}
Widget _buildAnimatedWidget(Widget child, int index) {
if (index >= _animations.length) return child;
final slideAnimation = Tween<Offset>(
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 Consumer<ThemeManager>(
builder: (context, themeManager, child) {
return AnimatedContainer(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOutCubic,
color: AppColors.scaffoldBackground,
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: const ProfileAppBar(title: 'Profile'),
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: [
GestureDetector(
onTap: () => showCountryDialog(context),
child: _buildInfoTile(
icon: SvgPicture.asset(
Assets.icons.globalSearch2.path,
width: 22,
),
title: 'Country',
trailing: Text(
'United Arab Emirates',
style: TextStyle(
color: AppColors.primary,
fontSize: 15,
fontWeight: FontWeight.w500,
),
),
),
),
GestureDetector(
onTap: () {
showLanguageSelectionOverlay(
context,
_currentLanguage,
(language, flag) {
setState(() {
_currentLanguage = language;
_currentFlag = flag;
});
},
_languageTileKey,
);
},
child: Container(
key: _languageTileKey,
child: _buildInfoTile(
icon: SvgPicture.asset(
Assets.icons.languageSquare.path,
width: 22,
),
title: 'Language',
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: ClipRRect(
key: ValueKey(_currentFlag),
borderRadius: BorderRadius.circular(4),
child: _currentFlag == 'placeholder'
? Container(
width: 24,
height: 18,
decoration: BoxDecoration(
color: AppColors.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(4),
),
child: Icon(
Icons.flag,
color: AppColors.primary,
size: 12,
),
)
: _currentFlag.endsWith('.svg')
? SvgPicture.asset(
_currentFlag,
width: 24,
height: 18,
)
: Image.asset(
_currentFlag,
width: 24,
height: 18,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 24,
height: 18,
decoration: BoxDecoration(
color: AppColors.greyBorder.withOpacity(0.2),
borderRadius: BorderRadius.circular(4),
),
child: Icon(
Icons.flag,
color: AppColors.textSecondary,
size: 12,
),
);
},
),
),
),
const SizedBox(width: 8),
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: Text(
_currentLanguage,
key: ValueKey(_currentLanguage),
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
),
),
const SizedBox(width: 8),
SvgPicture.asset(
Assets.icons.arrowRight.path,
color: AppColors.textPrimary,
),
],
),
),
),
),
CustomSwitchTile(
icon: SvgPicture.asset(
Assets.icons.brush.path,
width: 22,
),
title: 'Dark mode',
value: themeManager.isDarkMode,
onChanged: (value) => themeManager.setTheme(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(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const NotificationSettingsPage(),
),
);
},
child: _buildDecoratedNavigationTile(
icon: SvgPicture.asset(
Assets.icons.notification.path,
color: AppColors.primary,
width: 22,
),
title: 'Notifications',
),
),
3,
),
const SizedBox(height: 8),
_buildAnimatedWidget(
PressableListItem(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const TransactionsWalletsPage(),
),
);
},
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.heart.path, width: 22),
title: 'Favorite Stores',
),
),
7,
),
const SizedBox(height: 24),
_buildAnimatedWidget(_SectionTitle(title: 'Preferences'), 8),
_buildAnimatedWidget(
PressableListItem(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const LegalAndPoliciesPage(),
),
);
},
child: _buildDecoratedNavigationTile(
icon: SvgPicture.asset(Assets.icons.shield.path, width: 22),
title: 'Legal & Policies',
),
),
9,
),
const SizedBox(height: 8),
_buildAnimatedWidget(
PressableListItem(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const HelpAndSupportPage(),
),
);
},
child: _buildDecoratedNavigationTile(
icon: SvgPicture.asset(
Assets.icons.messageQuestion.path,
width: 22,
),
title: 'Help & Support',
),
),
10,
),
const SizedBox(height: 8),
_buildAnimatedWidget(
PressableListItem(
onTap: () => showLogoutDialog(context),
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: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
),
),
trailing,
],
),
);
}
Widget _buildDecoratedNavigationTile({
required Widget icon,
required String title,
}) {
return Container(
decoration: BoxDecoration(
color: AppColors.profileField,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: AppColors.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: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
),
),
SvgPicture.asset(Assets.icons.arrowRight.path, color: AppColors.textPrimary),
],
),
),
);
}
Widget _buildLogoutButton() {
return Container(
decoration: BoxDecoration(
color: AppColors.profileField,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: AppColors.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),
Expanded(
child: Text(
'Logout',
style: TextStyle(
color: AppColors.allReviewOpener,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
);
}
}
class PressableListItem extends StatefulWidget {
final Widget child;
final VoidCallback? onTap;
const PressableListItem({super.key, required this.child, this.onTap});
@override
State<PressableListItem> createState() => _PressableListItemState();
}
class _PressableListItemState extends State<PressableListItem>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _scaleAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 150),
reverseDuration: const Duration(milliseconds: 300),
);
_scaleAnimation = Tween<double>(
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: widget.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: TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
color: AppColors.textPrimary,
),
),
);
}
}