import 'package:flutter/material.dart'; import '../../../../core/locator/locator.dart'; import '../../../../core/theme/app_theme.dart'; import '../../data/data_source/remote/chat_api_provider.dart'; import '../../domain/entities/chat_pack.dart'; /// پنلِ «بسته چت» شبیه تصویرِ مرجع: هدرِ ربانِ طلایی، تب برای هر بسته، و گریدِ /// پیام‌ها/شکلک‌ها. بسته‌های قفل (نخریده) با دکمه‌ی خرید (سکه/VIP) نشان داده می‌شوند. class ChatPanel extends StatefulWidget { final void Function(String text) onText; final void Function(String emoji) onEmoji; final VoidCallback? onWalletChanged; // پس از خرید، موجودی را تازه کن const ChatPanel({ super.key, required this.onText, required this.onEmoji, this.onWalletChanged, }); static Future show( BuildContext context, { required void Function(String text) onText, required void Function(String emoji) onEmoji, VoidCallback? onWalletChanged, }) { return showDialog( context: context, barrierColor: Colors.black87, builder: (_) => ChatPanel( onText: onText, onEmoji: onEmoji, onWalletChanged: onWalletChanged, ), ); } @override State createState() => _ChatPanelState(); } class _ChatPanelState extends State { final _api = locator(); late Future> _future; String? _busyPack; // بسته‌ای که در حالِ خرید است @override void initState() { super.initState(); _future = _api.getChatPacks(); } void _reload() => setState(() => _future = _api.getChatPacks()); Future _buy(ChatPack p) async { setState(() => _busyPack = p.id); final err = await _api.buyChatPack(p.id); if (!mounted) return; setState(() => _busyPack = null); if (err == null) { widget.onWalletChanged?.call(); _reload(); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(err), duration: const Duration(seconds: 2)), ); } } void _pick(ChatPack p, String body) { if (p.isEmoji) { widget.onEmoji(body); } else { widget.onText(body); } Navigator.pop(context); } @override Widget build(BuildContext context) { return Dialog( backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 40), child: FutureBuilder>( future: _future, builder: (context, snap) { if (snap.connectionState != ConnectionState.done) { return const SizedBox( height: 200, child: Center( child: CircularProgressIndicator(color: AppColors.gold)), ); } final packs = snap.data ?? const []; if (packs.isEmpty) { return _shell(const Center( child: Text('بسته‌ای موجود نیست', style: TextStyle(color: Colors.white70)))); } return DefaultTabController( length: packs.length, child: _shell( Column( mainAxisSize: MainAxisSize.min, children: [ TabBar( isScrollable: true, tabAlignment: TabAlignment.center, indicator: BoxDecoration( color: const Color(0xFF7B0E14), borderRadius: BorderRadius.circular(10), border: Border.all(color: AppColors.gold, width: 1.4), ), indicatorSize: TabBarIndicatorSize.tab, labelColor: AppColors.gold, unselectedLabelColor: Colors.white70, labelStyle: const TextStyle(fontWeight: FontWeight.bold), dividerColor: Colors.transparent, tabs: [for (final p in packs) Tab(text: p.title)], ), const SizedBox(height: 10), SizedBox( height: 320, child: TabBarView( children: [for (final p in packs) _packView(p)], ), ), ], ), ), ); }, ), ); } // قابِ قرمزِ پنل با ربانِ طلاییِ «بسته چت» و دکمه‌ی بستن. Widget _shell(Widget child) { return Stack( clipBehavior: Clip.none, children: [ Container( margin: const EdgeInsets.only(top: 18), padding: const EdgeInsets.fromLTRB(12, 30, 12, 14), decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFF8E0E1B), Color(0xFF5A0A12)], ), borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.gold, width: 2), ), child: child, ), // ربانِ عنوان Positioned( top: 0, left: 0, right: 0, child: Center( child: Container( padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 6), decoration: BoxDecoration( gradient: const LinearGradient( colors: [AppColors.gold, AppColors.goldDark], ), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white24), ), child: const Text('بسته چت', style: TextStyle( color: Color(0xFF3A0A12), fontSize: 17, fontWeight: FontWeight.bold)), ), ), ), Positioned( top: 14, right: 6, child: GestureDetector( onTap: () => Navigator.pop(context), child: const CircleAvatar( radius: 15, backgroundColor: Color(0xFFB81D2A), child: Icon(Icons.close, color: Colors.white, size: 18), ), ), ), ], ); } Widget _packView(ChatPack p) { final grid = p.isEmoji ? _emojiGrid(p) : _textGrid(p); if (p.owned) return grid; // بسته‌ی قفل: گرید کم‌رنگ + دکمه‌ی خرید روی آن. return Stack( children: [ IgnorePointer(child: Opacity(opacity: 0.35, child: grid)), Center(child: _buyCard(p)), ], ); } Widget _buyCard(ChatPack p) { final busy = _busyPack == p.id; return Container( padding: const EdgeInsets.all(16), margin: const EdgeInsets.symmetric(horizontal: 24), decoration: BoxDecoration( color: const Color(0xCC2A0710), borderRadius: BorderRadius.circular(14), border: Border.all(color: AppColors.gold, width: 1.5), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ if (p.vip) const Padding( padding: EdgeInsets.only(bottom: 10), child: Text('این بسته برای بازیکنان VIP رایگان است!', textAlign: TextAlign.center, style: TextStyle(color: AppColors.gold, fontSize: 13)), ), ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: AppColors.success, minimumSize: const Size(160, 46), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: const BorderSide(color: AppColors.gold, width: 1.4), ), ), onPressed: busy ? null : () => _buy(p), icon: busy ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white)) : const Icon(Icons.monetization_on, color: AppColors.gold), label: Text('${p.priceCoins}', style: const TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold)), ), ], ), ); } Widget _textGrid(ChatPack p) => GridView.count( crossAxisCount: 2, padding: const EdgeInsets.all(4), childAspectRatio: 2.7, mainAxisSpacing: 10, crossAxisSpacing: 10, children: [ for (final m in p.messages) GestureDetector( onTap: p.owned ? () => _pick(p, m) : null, child: Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 6), decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFF9A1622), Color(0xFF5E0E16)], ), borderRadius: BorderRadius.circular(10), border: Border.all(color: AppColors.goldDark, width: 1.2), ), child: Text(m, maxLines: 2, textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold)), ), ), ], ); Widget _emojiGrid(ChatPack p) => GridView.count( crossAxisCount: 5, padding: const EdgeInsets.all(6), children: [ for (final e in p.messages) InkWell( borderRadius: BorderRadius.circular(12), onTap: p.owned ? () => _pick(p, e) : null, child: Center(child: Text(e, style: const TextStyle(fontSize: 32))), ), ], ); }