import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../core/theme/app_theme.dart'; import '../lobby/wallet_cubit.dart'; import 'shop_cubit.dart'; import 'shop_models.dart'; /// صفحه‌ی فروشگاه با تب‌های سکه/بلیط/کارت/تجهیزات. class ShopScreen extends StatelessWidget { const ShopScreen({super.key}); @override Widget build(BuildContext context) { return DefaultTabController( length: 4, child: Scaffold( appBar: AppBar( title: const Text('فروشگاه'), actions: [ BlocBuilder( builder: (context, s) => Center( child: Padding( padding: const EdgeInsets.only(left: 12), child: Row(children: [ const Icon(Icons.monetization_on, color: AppColors.gold, size: 18), const SizedBox(width: 4), Text('${s.wallet?.coins ?? 0}', style: const TextStyle(color: AppColors.text)), ]), ), ), ), ], bottom: const TabBar( isScrollable: true, labelColor: AppColors.gold, indicatorColor: AppColors.gold, tabs: [ Tab(text: 'سکه'), Tab(text: 'بلیط'), Tab(text: 'کارت'), Tab(text: 'تجهیزات'), ], ), ), body: BlocConsumer( listener: (context, state) {}, builder: (context, state) { if (state.status == ShopStatus.loading || state.status == ShopStatus.initial) { return const Center(child: CircularProgressIndicator()); } if (state.status == ShopStatus.error || state.data == null) { return Center( child: Column(mainAxisSize: MainAxisSize.min, children: [ const Text('خطا در بارگذاری فروشگاه'), TextButton( onPressed: () => context.read().load(), child: const Text('تلاش مجدد'), ), ]), ); } final d = state.data!; return TabBarView( children: [ _CoinsTab(packages: d.coinPackages), _TicketsTab(packages: d.ticketPackages), _CardsTab(data: d), _BoostersTab(boosters: d.boosters), ], ); }, ), ), ); } } /// اجرای یک عملیات فروشگاه و نمایش نتیجه + بازخوانی کیف‌پول. Future _do(BuildContext context, Future Function() action) async { final msg = await action(); if (!context.mounted || msg.isEmpty) return; await context.read().load(); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); } class _CoinsTab extends StatelessWidget { final List packages; const _CoinsTab({required this.packages}); @override Widget build(BuildContext context) { return GridView.count( crossAxisCount: 2, padding: const EdgeInsets.all(12), childAspectRatio: 0.82, mainAxisSpacing: 12, crossAxisSpacing: 12, children: [ _FreeCoinCard( onTap: () => _do(context, () => context.read().claimAd()), ), for (final p in packages) _StoreCard( title: p.title, badge: p.bonusPct > 0 ? '+${p.bonusPct}%' : null, lines: [ '${p.coins} سکه', if (p.vipDays > 0) '${p.vipDays} روز VIP', ], priceLabel: '${p.priceToman} تومان', icon: Icons.savings, onTap: () => _do(context, () => context.read().purchase('coin', p.id)), ), ], ); } } class _TicketsTab extends StatelessWidget { final List packages; const _TicketsTab({required this.packages}); @override Widget build(BuildContext context) { return GridView.count( crossAxisCount: 2, padding: const EdgeInsets.all(12), childAspectRatio: 0.82, mainAxisSpacing: 12, crossAxisSpacing: 12, children: [ for (final p in packages) _StoreCard( title: p.title, lines: ['${p.tickets} بلیط'], priceLabel: '${p.priceToman} تومان', icon: Icons.confirmation_number, onTap: () => _do(context, () => context.read().purchase('ticket', p.id)), ), ], ); } } class _BoostersTab extends StatelessWidget { final List boosters; const _BoostersTab({required this.boosters}); @override Widget build(BuildContext context) { return GridView.count( crossAxisCount: 2, padding: const EdgeInsets.all(12), childAspectRatio: 0.82, mainAxisSpacing: 12, crossAxisSpacing: 12, children: [ for (final b in boosters) _StoreCard( title: b.title, lines: ['تجربه ×${b.multiplier}', '${b.hours} ساعت'], priceLabel: '${b.priceToman} تومان', icon: Icons.bolt, onTap: () => _do(context, () => context.read().purchase('booster', b.id)), ), ], ); } } class _CardsTab extends StatelessWidget { final ShopData data; const _CardsTab({required this.data}); @override Widget build(BuildContext context) { return GridView.count( crossAxisCount: 2, padding: const EdgeInsets.all(12), childAspectRatio: 0.82, mainAxisSpacing: 12, crossAxisSpacing: 12, children: [ for (final c in data.cardSkins) _CardSkinCard( skin: c, owned: data.owns(c.id), selected: data.selectedCard == c.id, ), ], ); } } class _CardSkinCard extends StatelessWidget { final CardSkin skin; final bool owned; final bool selected; const _CardSkinCard( {required this.skin, required this.owned, required this.selected}); @override Widget build(BuildContext context) { final Widget action; if (selected) { action = const _Pill(text: 'انتخاب شده', color: AppColors.goldDark); } else if (owned) { action = _ActionButton( label: 'انتخاب', color: AppColors.green, onTap: () => _do(context, () => context.read().selectCard(skin.id)), ); } else { action = _ActionButton( label: '${skin.priceCoins} سکه', color: AppColors.accent, onTap: () => _do(context, () => context.read().buyCard(skin.id)), ); } return _Panel( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(skin.title, textAlign: TextAlign.center, style: const TextStyle(color: AppColors.gold)), const Icon(Icons.style, size: 48, color: AppColors.text), SizedBox(width: double.infinity, child: action), ], ), ); } } class _FreeCoinCard extends StatelessWidget { final VoidCallback onTap; const _FreeCoinCard({required this.onTap}); @override Widget build(BuildContext context) { return _Panel( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('سکه رایگان', textAlign: TextAlign.center, style: TextStyle(color: AppColors.gold)), const Icon(Icons.ondemand_video, size: 44, color: AppColors.green), const Text('با دیدن تبلیغ', style: TextStyle(color: Colors.white60, fontSize: 12)), SizedBox( width: double.infinity, child: _ActionButton( label: 'رایگان', color: AppColors.green, onTap: onTap), ), ], ), ); } } class _StoreCard extends StatelessWidget { final String title; final List lines; final String priceLabel; final IconData icon; final String? badge; final VoidCallback onTap; const _StoreCard({ required this.title, required this.lines, required this.priceLabel, required this.icon, required this.onTap, this.badge, }); @override Widget build(BuildContext context) { return Stack( children: [ _Panel( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(title, textAlign: TextAlign.center, style: const TextStyle(color: AppColors.gold)), Icon(icon, size: 40, color: AppColors.gold), Column( children: [ for (final l in lines) Text(l, style: const TextStyle(color: AppColors.text)), ], ), SizedBox( width: double.infinity, child: _ActionButton( label: priceLabel, color: AppColors.accent, onTap: onTap), ), ], ), ), if (badge != null) Positioned( top: 4, left: 4, child: _Pill(text: badge!, color: AppColors.green), ), ], ); } } class _Panel extends StatelessWidget { final Widget child; const _Panel({required this.child}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: AppColors.panel, borderRadius: BorderRadius.circular(14), border: Border.all(color: AppColors.goldDark), ), child: child, ); } } class _ActionButton extends StatelessWidget { final String label; final Color color; final VoidCallback onTap; const _ActionButton( {required this.label, required this.color, required this.onTap}); @override Widget build(BuildContext context) { final busy = context.select((ShopCubit c) => c.state.busy); return ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: color, minimumSize: const Size.fromHeight(38), padding: const EdgeInsets.symmetric(horizontal: 6), ), onPressed: busy ? null : onTap, child: Text(label, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 13)), ); } } class _Pill extends StatelessWidget { final String text; final Color color; const _Pill({required this.text, required this.color}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(8), ), child: Text(text, style: const TextStyle(color: Colors.white, fontSize: 12)), ); } }