import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import '../../core/app_colors.dart'; import '../../domain/entities/payment_card.dart'; import '../components/custom_app_bar.dart'; import '../event/payment_methods_event.dart'; import '../state/payment_methods_state.dart'; import '../viewmodel/payment_methods_bloc.dart'; class PaymentMethodsScreen extends StatelessWidget { const PaymentMethodsScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: const BoxDecoration(gradient: AppColors.phoneScreenBg), child: SafeArea( child: Column( children: [ const Padding( padding: EdgeInsets.symmetric(horizontal: 20), child: CustomAppBar(title: 'Способы оплаты'), ), const SizedBox(height: 24), Expanded( child: BlocConsumer( listener: (context, state) { if (state.status == PaymentMethodsStatus.failure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.errorMessage ?? 'Ошибка')), ); } }, builder: (context, state) { if (state.status == PaymentMethodsStatus.loading && state.cards.isEmpty) { return const Center(child: CircularProgressIndicator(color: Color(0xFF00D4AA))); } return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildBalanceCard(context, state.balance), const SizedBox(height: 20), _buildCardsList(context, state), ], ), ); }, ), ), ], ), ), ), ); } Widget _buildBalanceCard(BuildContext context, int balance) { return Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( gradient: AppColors.activeButtonGradient, borderRadius: BorderRadius.circular(20), ), child: Stack( clipBehavior: Clip.none, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Баланс', style: TextStyle(color: Color(0xFF0A0F2E), fontSize: 16, fontWeight: FontWeight.w600), ), const SizedBox(height: 8), Row( crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ Text( balance.toStringAsFixed(2), style: TextStyle(color: Color(0xFF0A0F2E), fontSize: 32, fontWeight: FontWeight.bold), ), const SizedBox(width: 4), Text( 'баллов', style: TextStyle(color: const Color(0xFF0A0F2E).withOpacity(0.7), fontSize: 14), ), ], ), const SizedBox(height: 20), _buildTopUpBalanceButton(context), ], ), Positioned( right: -30, top: -50, child: Image.asset('assets/icons/card-screen.png', width: 100, height: 100, fit: BoxFit.contain), ), ], ), ); } Widget _buildCardsList(BuildContext context, PaymentMethodsState state) { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: const Color(0xFF0A0F2E).withOpacity(0.65), borderRadius: BorderRadius.circular(20), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Карты', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.w600), ), const SizedBox(height: 16), if (state.cards.isEmpty && state.status == PaymentMethodsStatus.success) const Padding( padding: EdgeInsets.symmetric(vertical: 20), child: Text('У вас пока нет привязанных карт', style: TextStyle(color: Colors.white70)), ), ...state.cards.asMap().entries.map((entry) { final index = entry.key; final card = entry.value; return Column( children: [ _CardItem( card: card, onDelete: () => context.read().add(PaymentMethodsDeleteCard(card.id)), onMakeMain: card.isMain ? null : () => context.read().add(PaymentMethodsSetMainCard(card.id)), ), if (index < state.cards.length - 1) const SizedBox(height: 16), ], ); }).toList(), const SizedBox(height: 20), _buildAddCardButton(context), ], ), ); } Widget _buildAddCardButton(BuildContext context) { return Container( height: 48, decoration: BoxDecoration( color: const Color(0xFF0A0F2E), borderRadius: BorderRadius.circular(24), ), child: Material( color: Colors.transparent, child: InkWell( onTap: () => context.go('/home/payment-methods/add-card'), borderRadius: BorderRadius.circular(24), child: const Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ Icon(Icons.credit_card, color: Color(0xFF00D4AA), size: 24), SizedBox(width: 12), Expanded( child: Text( 'Привязать карту', style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w600), ), ), Icon(Icons.add, color: Color(0xFF00D4AA), size: 24), ], ), ), ), ), ); } Widget _buildTopUpBalanceButton(BuildContext context) { return Container( height: 48, decoration: BoxDecoration( color: const Color(0xFF0A0F2E), borderRadius: BorderRadius.circular(24), ), child: Material( color: Colors.transparent, child: InkWell( onTap: () => context.go('/home/payment-methods/top-up'), borderRadius: BorderRadius.circular(24), child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ Image.asset("assets/icons/money_icon.png", width: 24, height: 24), SizedBox(width: 12), Expanded( child: Text( 'Пополнить баланс', style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w600), ), ), Icon(Icons.add, color: Color(0xFF00D4AA), size: 24), ], ), ), ), ), ); } } class _CardItem extends StatelessWidget { final PaymentCard card; final VoidCallback onDelete; final VoidCallback? onMakeMain; const _CardItem({ required this.card, required this.onDelete, this.onMakeMain, }); @override Widget build(BuildContext context) { return Row( children: [ Image.asset( _getDefaultIconPath(card.type), width: 40, height: 40, fit: BoxFit.contain, ), const SizedBox(width: 12), Expanded( child: GestureDetector( onTap: onMakeMain, // Нажатие на текст карты делает её основной behavior: HitTestBehavior.opaque, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${card.type} ****${card.cardLastNumber}', style: const TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w600), ), const SizedBox(height: 4), Text( card.isMain ? 'основная' : 'сделать основной', style: TextStyle( color: card.isMain ? const Color(0xFF66E3C4) : Colors.white.withOpacity(0.5), fontSize: 12, ), ), ], ), ), ), GestureDetector( onTap: onDelete, child: const Icon(Icons.close, color: Color(0xFF00D4AA), size: 20), ), ], ); } String _getDefaultIconPath(String cardType) { switch (cardType) { case 'Belcard': return 'assets/icons/belcard.png'; case 'Visa': return 'assets/icons/visa.png'; case 'Maestro': return 'assets/icons/maestro.png'; case 'Mir': return 'assets/icons/mir.png'; case 'Mastercard': return 'assets/icons/mastercard.png'; default: return 'assets/icons/belcard.png'; } } }