import 'package:flutter/material.dart'; import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter; import 'package:go_router/go_router.dart'; import 'package:random_avatar/random_avatar.dart'; import '../../core/network/api_client.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/game_ui.dart'; /// صفحه‌ی پروفایل: نام، آواتار، سطح، جام‌ها و آمارِ بازی. /// نمایشِ آمار ویژه‌ی کاربرانِ VIP است (سرور هم این محدودیت را اعمال می‌کند). class ProfileScreen extends StatefulWidget { final ApiClient api; const ProfileScreen({super.key, required this.api}); @override State createState() => _ProfileScreenState(); } class _ProfileData { final String name; final String avatar; final String mobile; final int level; final int trophies; final int xpInto; final int xpNext; final bool vip; final Map? stats; // null یعنی قفل (غیر VIP) _ProfileData({ required this.name, required this.avatar, required this.mobile, required this.level, required this.trophies, required this.xpInto, required this.xpNext, required this.vip, required this.stats, }); } class _ProfileScreenState extends State { late Future<_ProfileData> _future; @override void initState() { super.initState(); _future = _load(); } Future<_ProfileData> _load() async { final dio = widget.api.dio; final res = await Future.wait([ dio.get('/me'), dio.get('/wallet'), dio.get('/stats'), ]); final user = (res[0].data['user'] ?? {}) as Map; final w = (res[1].data ?? {}) as Map; final s = (res[2].data ?? {}) as Map; final name = (user['first_name'] as String?)?.trim(); final avatar = (user['avatar'] as String?)?.trim(); return _ProfileData( name: (name == null || name.isEmpty) ? 'بازیکن' : name, avatar: (avatar == null || avatar.isEmpty) ? 'hakem-1' : avatar, mobile: (user['mobile'] as String?) ?? '', level: (w['level'] ?? 1) as int, trophies: (w['trophies'] ?? 0) as int, xpInto: (w['xp_into_level'] ?? 0) as int, xpNext: (w['xp_for_next'] ?? 1) as int, vip: (s['vip'] ?? false) as bool, stats: (s['stats'] as Map?)?.cast(), ); } @override Widget build(BuildContext context) { return Scaffold( body: GameBackground( child: SafeArea( child: FutureBuilder<_ProfileData>( future: _future, builder: (context, snap) { if (snap.connectionState != ConnectionState.done) { return const Center( child: CircularProgressIndicator(color: AppColors.gold), ); } if (snap.hasError || !snap.hasData) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Text( 'خطا در دریافت پروفایل', style: TextStyle(color: Colors.white70), ), const SizedBox(height: 12), GameButton( label: 'تلاش دوباره', onTap: () => setState(() { _future = _load(); }), ), ], ), ); } return _content(context, snap.data!); }, ), ), ), ); } // ویرایش نام و آواتار؛ پس از ذخیره، پروفایل دوباره بارگذاری می‌شود. Future _editProfile(_ProfileData d) async { final result = await showModalBottomSheet>( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (_) => _EditProfileSheet(name: d.name, avatar: d.avatar), ); if (result == null || !mounted) return; try { await widget.api.dio.post( '/profile', data: {'first_name': result['name'], 'avatar': result['avatar']}, ); if (!mounted) return; setState(() { _future = _load(); }); } catch (e) { print(e); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('ذخیره نشد، دوباره تلاش کنید')), ); } } Widget _content(BuildContext context, _ProfileData d) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( children: [ Row( children: [ IconButton( onPressed: () => context.pop(), icon: const Icon(Icons.arrow_back, color: AppColors.gold), ), const Spacer(), const GlowText('پروفایل', size: 24), const Spacer(), const SizedBox(width: 48), ], ), const SizedBox(height: 8), GamePanel( child: Column( children: [ Stack( children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: AppColors.gold, width: 2.5), ), child: RandomAvatar(d.avatar, height: 92, width: 92), ), Positioned( bottom: 0, right: 0, child: GestureDetector( onTap: () => _editProfile(d), child: Container( padding: const EdgeInsets.all(6), decoration: const BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [Color(0xFFFFD54F), Color(0xFFB8860B)], ), ), child: const Icon( Icons.edit, color: Color(0xFF3A0A12), size: 18, ), ), ), ), ], ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Flexible(child: GlowText(d.name, size: 22)), if (d.vip) ...[const SizedBox(width: 8), const _VipBadge()], ], ), if (d.mobile.isNotEmpty) Text( d.mobile, style: const TextStyle(color: Colors.white38, fontSize: 12), ), const SizedBox(height: 14), Row( children: [ Expanded( child: _MiniStat( icon: Icons.star, label: 'سطح', value: '${d.level}', ), ), Expanded( child: _MiniStat( icon: Icons.emoji_events, label: 'جام', value: '${d.trophies}', ), ), ], ), const SizedBox(height: 10), ClipRRect( borderRadius: BorderRadius.circular(5), child: LinearProgressIndicator( value: d.xpNext == 0 ? 0 : d.xpInto / d.xpNext, minHeight: 8, backgroundColor: Colors.white10, valueColor: const AlwaysStoppedAnimation(AppColors.gold), ), ), Padding( padding: const EdgeInsets.only(top: 4), child: Text( '${d.xpInto} / ${d.xpNext} XP', style: const TextStyle(color: Colors.white38, fontSize: 11), ), ), ], ), ), const SizedBox(height: 16), const Align( alignment: Alignment.centerRight, child: GlowText('آمار بازی', size: 18), ), const SizedBox(height: 8), _statsSection(context, d), ], ), ); } Widget _statsSection(BuildContext context, _ProfileData d) { final rows = [ _StatRow('بازی کل', d.stats?['games'], Icons.casino), _StatRow('برد کل', d.stats?['wins'], Icons.thumb_up), _StatRow('باخت کل', d.stats?['losses'], Icons.thumb_down), _StatRow('کُت کردن', d.stats?['kot_made'], Icons.flash_on), _StatRow('کُت شدن', d.stats?['kot_received'], Icons.flash_off), _StatRow('بریدن', d.stats?['cuts'], Icons.bolt), _StatRow('دست حاکم', d.stats?['hakem_count'], Icons.workspace_premium), ]; final panel = GamePanel(child: Column(children: rows)); if (d.vip) return panel; // غیر VIP: آمار قفل است؛ روی آن لایه‌ی قفل و دعوت به اشتراک نشان بده. return Stack( children: [ // محتوای محو زیرِ قفل (مقادیر نامشخص) Opacity(opacity: 0.35, child: IgnorePointer(child: panel)), Positioned.fill( child: Container( decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.45), borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.goldDark), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.lock, color: AppColors.gold, size: 36), const SizedBox(height: 8), const Padding( padding: EdgeInsets.symmetric(horizontal: 24), child: Text( 'مشاهده‌ی آمار ویژه‌ی کاربران VIP است', textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontSize: 14), ), ), const SizedBox(height: 12), GameButton( label: 'تهیه اشتراک VIP', icon: Icons.workspace_premium, colors: const [Color(0xFFFFC107), Color(0xFFB8860B)], onTap: () async { await context.push('/vip'); if (context.mounted) setState(() { _future = _load(); }); }, ), ], ), ), ), ], ); } } class _StatRow extends StatelessWidget { final String label; final Object? value; final IconData icon; const _StatRow(this.label, this.value, this.icon); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 7), child: Row( children: [ Icon(icon, color: AppColors.gold, size: 20), const SizedBox(width: 10), Text( label, style: const TextStyle(color: Colors.white, fontSize: 15), ), const Spacer(), Text( '${value ?? '—'}', style: const TextStyle( color: AppColors.gold, fontSize: 16, fontWeight: FontWeight.bold, ), ), ], ), ); } } class _MiniStat extends StatelessWidget { final IconData icon; final String label; final String value; const _MiniStat({ required this.icon, required this.label, required this.value, }); @override Widget build(BuildContext context) { return Column( children: [ Icon(icon, color: AppColors.gold, size: 22), const SizedBox(height: 2), Text( value, style: const TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), Text( label, style: const TextStyle(color: Colors.white54, fontSize: 12), ), ], ); } } /// شیتِ ویرایش نام و آواتار (با کلیک «تأیید» مقدار جدید برگردانده می‌شود). class _EditProfileSheet extends StatefulWidget { final String name; final String avatar; const _EditProfileSheet({required this.name, required this.avatar}); @override State<_EditProfileSheet> createState() => _EditProfileSheetState(); } class _EditProfileSheetState extends State<_EditProfileSheet> { late final TextEditingController _name; late final List _seeds; late String _selected; @override void initState() { super.initState(); _name = TextEditingController(text: widget.name); _seeds = List.generate(12, (i) => 'hakem-${i + 1}'); // آواتارِ فعلی را در شبکه نگه دار حتی اگر جزو seedهای پیش‌فرض نباشد. if (!_seeds.contains(widget.avatar)) _seeds.insert(0, widget.avatar); _selected = widget.avatar; } @override void dispose() { _name.dispose(); super.dispose(); } bool get _valid => _name.text.trim().length >= 2; @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), child: Container( decoration: const BoxDecoration( color: AppColors.bgDark, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), border: Border(top: BorderSide(color: AppColors.gold, width: 2)), ), padding: const EdgeInsets.all(18), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ const GlowText('ویرایش پروفایل', size: 20), const SizedBox(height: 14), Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: AppColors.gold, width: 2), ), child: RandomAvatar(_selected, height: 72, width: 72), ), const SizedBox(height: 12), TextField( controller: _name, textAlign: TextAlign.center, maxLength: 20, inputFormatters: [LengthLimitingTextInputFormatter(20)], decoration: const InputDecoration( hintText: 'نام نمایشی (۲ تا ۲۰ حرف)', counterText: '', ), onChanged: (_) => setState(() {}), ), const SizedBox(height: 10), const Align( alignment: Alignment.centerRight, child: Text( 'انتخاب آواتار', style: TextStyle(color: AppColors.gold), ), ), const SizedBox(height: 8), GridView.count( crossAxisCount: 4, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), mainAxisSpacing: 10, crossAxisSpacing: 10, children: [ for (final s in _seeds) GestureDetector( onTap: () => setState(() => _selected = s), child: Container( decoration: BoxDecoration( shape: BoxShape.circle, color: AppColors.panel, border: Border.all( color: _selected == s ? AppColors.gold : Colors.transparent, width: 2.5, ), ), child: RandomAvatar(s), ), ), ], ), const SizedBox(height: 16), GameButton( label: 'تأیید', width: double.infinity, colors: const [Color(0xFF3FA34D), Color(0xFF1B5E20)], onTap: _valid ? () => Navigator.pop(context, { 'name': _name.text.trim(), 'avatar': _selected, }) : null, ), ], ), ), ), ); } } class _VipBadge extends StatelessWidget { const _VipBadge(); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFFFFD54F), Color(0xFFB8860B)], ), borderRadius: BorderRadius.circular(8), ), child: const Text( 'VIP', style: TextStyle( color: Color(0xFF3A0A12), fontWeight: FontWeight.bold, fontSize: 12, ), ), ); } }