feat: add tournoment feature

This commit is contained in:
2026-07-07 15:18:55 +03:30
parent 5b0a66bb54
commit 5424695f25
10 changed files with 1349 additions and 229 deletions
@@ -52,99 +52,96 @@ class _LobbyScreenState extends State<LobbyScreen> {
builder: (context, state) {
final st = state.walletStatus;
final wallet = st is WalletLoaded ? st.wallet : null;
return Column(
children: [
_TopBar(wallet: wallet, onCoinTap: () => _openShop(context)),
Expanded(
child: Center(
return SafeArea(
child: Column(
children: [
_TopBar(wallet: wallet, onCoinTap: () => _openShop(context)),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 28),
padding: const EdgeInsets.fromLTRB(16, 6, 16, 8),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const GlowText('حاکم ایرانی', size: 44),
const SizedBox(height: 44),
GameButton(
label: 'بازی',
icon: Icons.style,
width: double.infinity,
colors: const [
Color(0xFFC2185B),
Color(0xFF6A0D38),
],
const SizedBox(height: 6),
const _LobbyHeader(),
const SizedBox(height: 18),
// اکشنِ اصلی: بازیِ سریع.
_PrimaryPlay(
onTap: () async {
await context.push('/game/tiers');
if (context.mounted) _reload();
},
),
const SizedBox(height: 16),
GameButton(
label: 'دورهمی',
icon: Icons.group_add,
width: double.infinity,
colors: const [
Color(0xFF1565C0),
Color(0xFF0A2E57),
const SizedBox(height: 14),
// اکشن‌های ثانویه در گریدِ دوستونه.
GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.55,
children: [
_ActionTile(
icon: Icons.group_add,
label: 'دورهمی',
sub: 'بازی با دوستان',
accent: AppColors.lapis,
onTap: () async {
await context.push('/private');
if (context.mounted) _reload();
},
),
_ActionTile(
icon: Icons.emoji_events,
label: 'تورنومنت',
sub: 'جایزه بگیر',
accent: const Color(0xFF9B7BE0),
onTap: () async {
await context.push('/tournaments');
if (context.mounted) _reload();
},
),
_ActionTile(
icon: Icons.leaderboard,
label: 'رتبه‌بندی',
sub: 'جدول قهرمانان',
accent: AppColors.gold,
onTap: () => context.push('/leaderboard'),
),
_ActionTile(
icon: Icons.storefront,
label: 'فروشگاه',
sub: 'سکه و آیتم',
accent: AppColors.success,
onTap: () => _openShop(context),
),
],
onTap: () async {
await context.push('/private');
if (context.mounted) _reload();
},
),
const SizedBox(height: 16),
GameButton(
label: 'رتبه‌بندی',
icon: Icons.leaderboard,
width: double.infinity,
colors: const [
Color(0xFFE9952F),
Color(0xFF9C5A00),
],
onTap: () => context.push('/leaderboard'),
),
const SizedBox(height: 16),
GameButton(
label: 'فروشگاه',
icon: Icons.storefront,
width: double.infinity,
colors: const [
Color(0xFF7B1FA2),
Color(0xFF3E0A57),
],
onTap: () => _openShop(context),
),
const SizedBox(height: 16),
GameButton(
label: 'سکه روزانه',
icon: Icons.monetization_on,
width: double.infinity,
colors: const [
AppColors.success,
AppColors.successDark,
],
onTap:
() => context.read<WalletBloc>().add(
ClaimDailyEvent(),
),
const SizedBox(height: 14),
_DailyCard(
onTap: () => context
.read<WalletBloc>()
.add(ClaimDailyEvent()),
),
],
),
),
),
),
TextButton.icon(
onPressed: () {
context.read<AuthBloc>().add(LogoutEvent());
context.go('/login');
},
icon: const Icon(Icons.logout, color: Colors.white54),
label: const Text(
'خروج',
style: TextStyle(color: Colors.white54),
TextButton.icon(
onPressed: () {
context.read<AuthBloc>().add(LogoutEvent());
context.go('/login');
},
icon: const Icon(Icons.logout,
color: Colors.white38, size: 18),
label: const Text(
'خروج از حساب',
style: TextStyle(color: Colors.white38, fontSize: 13),
),
),
),
const SizedBox(height: 8),
],
],
),
);
},
),
@@ -158,6 +155,203 @@ class _LobbyScreenState extends State<LobbyScreen> {
}
}
/// عنوانِ لابی: تاجِ طلایی + نامِ بازی + زیرعنوان.
class _LobbyHeader extends StatelessWidget {
const _LobbyHeader();
@override
Widget build(BuildContext context) {
return Column(
children: const [
Icon(Icons.workspace_premium, color: AppColors.gold, size: 34),
SizedBox(height: 4),
GlowText('حاکم ایرانی', size: 36),
SizedBox(height: 2),
Text('بازیِ آنلاینِ حکم',
style: TextStyle(color: Colors.white54, fontSize: 13)),
],
);
}
}
/// اکشنِ اصلی: بازیِ سریع (میزِ عمومی) — کارتِ بزرگِ برجسته.
class _PrimaryPlay extends StatelessWidget {
final VoidCallback onTap;
const _PrimaryPlay({required this.onTap});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 18),
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [AppColors.lapis, AppColors.lapisHi, AppColors.lapisLo],
),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: AppColors.gold, width: 2),
boxShadow: [
BoxShadow(
color: AppColors.gold.withValues(alpha: 0.28), blurRadius: 16),
const BoxShadow(
color: Colors.black54, blurRadius: 10, offset: Offset(0, 5)),
],
),
child: Row(
children: [
Container(
width: 54,
height: 54,
decoration: const BoxDecoration(
gradient:
LinearGradient(colors: [AppColors.gold, AppColors.goldDark]),
shape: BoxShape.circle,
),
child:
const Icon(Icons.play_arrow_rounded, color: AppColors.lapisInk, size: 36),
),
const SizedBox(width: 14),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('بازی سریع',
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold)),
SizedBox(height: 2),
Text('ورود به میزِ عمومی',
style: TextStyle(color: Colors.white70, fontSize: 13)),
],
),
const Spacer(),
const Icon(Icons.arrow_back_ios_new,
color: AppColors.gold, size: 18),
],
),
),
);
}
}
/// کاشیِ اکشنِ ثانویه در گرید (آیکن + عنوان + زیرعنوان).
class _ActionTile extends StatelessWidget {
final IconData icon;
final String label;
final String sub;
final Color accent;
final VoidCallback onTap;
const _ActionTile({
required this.icon,
required this.label,
required this.sub,
required this.accent,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(18),
child: InkWell(
borderRadius: BorderRadius.circular(18),
onTap: onTap,
child: Ink(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [AppColors.lapisHi, AppColors.lapisLo],
),
borderRadius: BorderRadius.circular(18),
border: Border.all(color: AppColors.goldDark, width: 1.2),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(9),
decoration: BoxDecoration(
color: accent.withValues(alpha: 0.18),
shape: BoxShape.circle,
border: Border.all(color: accent.withValues(alpha: 0.6)),
),
child: Icon(icon, color: accent, size: 22),
),
const Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(label,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold)),
const SizedBox(height: 2),
Text(sub,
style:
const TextStyle(color: Colors.white54, fontSize: 11)),
],
),
],
),
),
),
);
}
}
/// کارتِ سکه‌ی روزانه (اکشنِ برجسته‌ی سبز-طلایی).
class _DailyCard extends StatelessWidget {
final VoidCallback onTap;
const _DailyCard({required this.onTap});
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(16),
child: InkWell(
borderRadius: BorderRadius.circular(16),
onTap: onTap,
child: Ink(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [AppColors.success, AppColors.successDark],
),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppColors.gold, width: 1.4),
),
child: Row(
children: const [
Icon(Icons.card_giftcard, color: Colors.white, size: 26),
SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('هدیه‌ی روزانه',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold)),
Text('هر روز سکه‌ی رایگان بگیر',
style: TextStyle(color: Colors.white70, fontSize: 12)),
],
),
Spacer(),
Icon(Icons.redeem, color: AppColors.gold, size: 22),
],
),
),
),
);
}
}
class _TopBar extends StatelessWidget {
final WalletEntity? wallet;
final VoidCallback onCoinTap;