import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:random_avatar/random_avatar.dart'; import '../../../../core/network/ws_client.dart'; import '../../../../core/theme/app_theme.dart'; import '../../../../core/widgets/game_ui.dart'; import '../bloc/game_bloc.dart'; import '../bloc/game_state.dart'; import 'game_screen.dart'; /// میز خصوصی: اتاق انتظار (کد، بازیکنان، شروع) سپس صحنه‌ی بازی (روی همان اتصال). class PrivateTableScreen extends StatelessWidget { const PrivateTableScreen({super.key}); @override Widget build(BuildContext context) { return BlocConsumer( listenWhen: (a, b) => (a.notice != b.notice && b.notice != null) || (!a.tableClosed && b.tableClosed), listener: (context, state) { if (state.tableClosed) { if (context.canPop()) context.pop(); return; } if (state.notice != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.notice!), duration: const Duration(seconds: 2), ), ); context.read().clearNotice(); } }, builder: (context, state) { if (state.state != null) { return const GameScreen(prize: 0); } return _LobbyView(state: state); }, ); } } class _LobbyView extends StatefulWidget { final GameUiState state; const _LobbyView({required this.state}); @override State<_LobbyView> createState() => _LobbyViewState(); } class _LobbyViewState extends State<_LobbyView> { int _hands = 3; // تعداد دستِ انتخابیِ میزبان void _leave() { context.read().leaveTable(); if (context.canPop()) context.pop(); } @override Widget build(BuildContext context) { final state = widget.state; final lobby = state.lobby; final connecting = state.connection != WsStatus.connected || lobby == null; return PopScope( canPop: false, onPopInvokedWithResult: (didPop, _) { if (!didPop) _leave(); }, child: Scaffold( body: GameBackground( child: SafeArea( child: Stack( children: [ Column( children: [ _topBar(context, lobby), Expanded( child: connecting ? const Center( child: CircularProgressIndicator( color: AppColors.gold, ), ) : _content(context, lobby), ), ], ), if (state.countdown != null) _CountdownOverlay(seconds: state.countdown!), ], ), ), ), ), ); } // نوار بالا: بازگشت (چپ) و اشتراک‌گذاریِ کد (راست). Widget _topBar(BuildContext context, TableLobby? lobby) { Widget btn(IconData icon, VoidCallback onTap) => GestureDetector( onTap: onTap, child: Container( width: 46, height: 46, decoration: BoxDecoration( color: AppColors.panel, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.gold, width: 1.5), ), child: Icon(icon, color: AppColors.gold), ), ); return Padding( padding: const EdgeInsets.all(10), child: Directionality( textDirection: TextDirection.ltr, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (lobby != null) btn(Icons.share, () { Clipboard.setData(ClipboardData(text: lobby.code)); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('کد میز کپی شد؛ برای دوستانت بفرست'), ), ); }), btn(Icons.arrow_forward, _leave), ], ), ), ); } Widget _content(BuildContext context, TableLobby lobby) { final youSeat = lobby.youSeat; // نگاشتِ جایگاهِ مطلق → بازیکن (خالی = بات هنگام شروع). final bySeat = {for (final p in lobby.players) p.seat: p}; // چیدمان از نگاهِ خودِ کاربر: «شما» پایین، هم‌تیمی (روبه‌رو) بالا، بقیه کنار. LobbyPlayer? seatAt(int rel) => bySeat[(youSeat + rel) % 4]; final me = seatAt(0); final top = seatAt(2); // هم‌تیمی (روبه‌رو) final left = seatAt(1); final right = seatAt(3); return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ const Text('شماره میز', style: TextStyle(color: Colors.white70)), const SizedBox(height: 4), GlowText(lobby.code, size: 36), const SizedBox(height: 8), // میز با چهار جایگاه. SizedBox( height: 340, child: Stack( children: [ Padding( padding: const EdgeInsets.symmetric( horizontal: 28, vertical: 36, ), child: Container( decoration: BoxDecoration( gradient: const RadialGradient( colors: [AppColors.lapisHi, AppColors.lapisLo], radius: 0.9, ), borderRadius: BorderRadius.circular(160), border: Border.all( color: const Color(0xFF8A5A12), width: 6, ), ), child: const Center(child: GlowText('سلطان حکم', size: 18)), ), ), Align(alignment: Alignment.topCenter, child: _seat(top, false)), Align( alignment: Alignment.centerLeft, child: _seat(left, false), ), Align( alignment: Alignment.centerRight, child: _seat(right, false), ), Align( alignment: Alignment.bottomCenter, child: _seat(me, true), ), // چرخشِ جایگاه‌ها (فقط میزبان) — تغییرِ تیم‌بندی. if (lobby.isHost) ...[ Align( alignment: const Alignment(-1, -0.35), child: _rotateBtn( Icons.rotate_left, () => context.read().rotateTable(-1), ), ), Align( alignment: const Alignment(1, -0.35), child: _rotateBtn( Icons.rotate_right, () => context.read().rotateTable(1), ), ), ], ], ), ), const SizedBox(height: 8), const Text('تعداد دست', style: TextStyle(color: Colors.white70)), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ for (final h in [3, 5, 7]) _handChip(h, lobby.isHost), ], ), const SizedBox(height: 20), if (lobby.isHost) GameButton( label: 'شروع بازی', icon: Icons.play_arrow, width: double.infinity, colors: const [AppColors.success, AppColors.successDark], onTap: () => context.read().startTable(_hands), ) else const Text( 'در انتظار شروع توسط میزبان…', style: TextStyle(color: AppColors.gold, fontSize: 15), ), const SizedBox(height: 6), if (lobby.isHost) const Text( 'جای‌های خالی با ربات پر می‌شوند', style: TextStyle(color: Colors.white54, fontSize: 12), ), const SizedBox(height: 20), ], ), ); } // یک جایگاهِ بازیکن دورِ میز (آواتار + ستاره + نام). Widget _seat(LobbyPlayer? p, bool isYou) { final empty = p == null; return Column( mainAxisSize: MainAxisSize.min, children: [ Stack( clipBehavior: Clip.none, children: [ Container( width: 62, height: 62, padding: const EdgeInsets.all(3), decoration: BoxDecoration( color: AppColors.bgDark, borderRadius: BorderRadius.circular(12), border: Border.all( color: isYou ? AppColors.gold : AppColors.goldDark, width: 2, ), ), child: empty ? const Icon( Icons.person_add_alt_1, color: Colors.white24, ) : ClipRRect( borderRadius: BorderRadius.circular(9), child: RandomAvatar(p.name), ), ), if (!empty) const Positioned( bottom: -6, left: -4, child: Icon(Icons.star, color: AppColors.gold, size: 22), ), ], ), const SizedBox(height: 6), Text( empty ? 'در انتظار' : (isYou ? 'شما' : p.name), maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: empty ? Colors.white38 : Colors.white, fontSize: 12, fontWeight: empty ? FontWeight.normal : FontWeight.bold, ), ), if (p?.host == true) const Text( 'میزبان', style: TextStyle(color: AppColors.gold, fontSize: 10), ), ], ); } // دکمه‌ی چرخشِ جایگاه‌ها (کنارِ میز). Widget _rotateBtn(IconData icon, VoidCallback onTap) { return GestureDetector( onTap: onTap, child: Container( width: 44, height: 44, decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [AppColors.lapisMid, AppColors.lapisLo], ), borderRadius: BorderRadius.circular(10), border: Border.all(color: AppColors.gold, width: 1.5), ), child: Icon(icon, color: AppColors.gold, size: 26), ), ); } Widget _handChip(int h, bool editable) { const fa = {3: '۳', 5: '۵', 7: '۷'}; final selected = _hands == h; return Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: GestureDetector( onTap: editable ? () => setState(() => _hands = h) : null, child: Container( width: 52, height: 52, alignment: Alignment.center, decoration: BoxDecoration( shape: BoxShape.circle, gradient: selected ? const LinearGradient( colors: [AppColors.gold, AppColors.goldDark], ) : null, color: selected ? null : AppColors.panel, border: Border.all( color: selected ? AppColors.gold : AppColors.goldDark, width: 2, ), ), child: Text( fa[h]!, style: TextStyle( color: selected ? AppColors.bg : Colors.white, fontSize: 22, fontWeight: FontWeight.bold, ), ), ), ), ); } } /// اوورلی شمارش معکوس ۳، ۲، ۱ پیش از شروع بازی. class _CountdownOverlay extends StatefulWidget { final int seconds; const _CountdownOverlay({required this.seconds}); @override State<_CountdownOverlay> createState() => _CountdownOverlayState(); } class _CountdownOverlayState extends State<_CountdownOverlay> { late int _n; Timer? _timer; @override void initState() { super.initState(); _n = widget.seconds; _timer = Timer.periodic(const Duration(seconds: 1), (_) { if (!mounted) return; setState(() => _n--); if (_n <= 0) _timer?.cancel(); }); } @override void dispose() { _timer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Container( color: Colors.black.withValues(alpha: 0.7), alignment: Alignment.center, child: TweenAnimationBuilder( key: ValueKey(_n), tween: Tween(begin: 0.4, end: 1.2), duration: const Duration(milliseconds: 700), curve: Curves.easeOut, builder: (context, scale, child) => Transform.scale(scale: scale, child: child), child: GlowText(_n > 0 ? '$_n' : 'شروع!', size: 96), ), ); } }