/opt/canhelp/apps/mobile/lib/screens/profile
NameSizeModeActions
edit_profile_screen.dart109830644editdlrm
payment_result_screen.dart72810644editdlrm
profile_balance_history_screen.dart93590644editdlrm
profile_blocked_users_screen.dart61430644editdlrm
profile_cards_screen.dart775370644editdlrm
profile_notifications_screen.dart57760644editdlrm
profile_plan_history_screen.dart124540644editdlrm
profile_portfolio_screen.dart162990644editdlrm
profile_referral_screen.dart94520644editdlrm
profile_reviews_screen.dart73200644editdlrm
profile_screen.dart356550644editdlrm
profile_site_screen.dart285510644editdlrm
profile_status_screen.dart156990644editdlrm
profile_topup_screen.dart108620644editdlrm
profile_widgets.dart151580644editdlrm
specialist_setup_screen.dart643980644editdlrm
support_ticket_screen.dart191010644editdlrm
Edit: /opt/canhelp/apps/mobile/lib/screens/profile/profile_balance_history_screen.dart (9359B)
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../../providers/locale_provider.dart'; import '../../services/api_client.dart'; import '../../theme/app_theme.dart'; import 'profile_widgets.dart'; class ProfileBalanceHistoryScreen extends StatefulWidget { const ProfileBalanceHistoryScreen({super.key}); @override State createState() => _ProfileBalanceHistoryScreenState(); } class _ProfileBalanceHistoryScreenState extends State { List> _rows = []; bool _loading = true; @override void initState() { super.initState(); _load(); } Future _load() async { setState(() => _loading = true); try { final rows = await ApiClient().getBalanceHistory(limit: 50); if (mounted) setState(() => _rows = rows); } catch (_) { if (mounted) setState(() => _rows = []); } finally { if (mounted) setState(() => _loading = false); } } String _kindLabel(LocaleProvider locale, String kind) { switch (kind) { case 'topup': return locale.t( 'profile.balanceHistory.kind.topup', 'Пополнение баланса', ); case 'plan_purchase': return locale.t( 'profile.balanceHistory.kind.planPurchase', 'Списание за тариф', ); case 'admin_topup': return locale.t( 'profile.balanceHistory.kind.adminTopUp', 'Пополнение администратором', ); default: return locale.t( 'profile.balanceHistory.kind.adminAdjustment', 'Корректировка администратором', ); } } @override Widget build(BuildContext context) { final locale = context.watch(); return Scaffold( backgroundColor: AppTheme.background, appBar: AppBar( backgroundColor: AppTheme.background, elevation: 0, scrolledUnderElevation: 0, foregroundColor: AppTheme.textPrimary, leading: IconButton( icon: const Icon( Icons.arrow_back_ios_new_rounded, size: 20, color: AppTheme.textPrimary, ), onPressed: () => context.canPop() ? context.pop() : context.go('/profile'), ), title: Text( locale.t('profile.balanceHistory.title', 'Архив баланса'), style: const TextStyle( fontWeight: FontWeight.w700, fontSize: 18, color: AppTheme.textPrimary, ), ), ), body: _loading ? const Center( child: CircularProgressIndicator(color: AppTheme.primary), ) : RefreshIndicator( onRefresh: _load, color: AppTheme.primary, child: _rows.isEmpty ? ListView( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 80, ), children: [ ProfileStateCard( icon: Icons.receipt_long_outlined, message: locale.t( 'profile.balanceHistory.empty', 'Операций пока нет', ), ), ], ) : ListView.separated( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), itemCount: _rows.length, separatorBuilder: (_, __) => const SizedBox(height: 8), itemBuilder: (_, index) { final row = _rows[index]; final isCredit = row['direction'] == 'credit'; final amount = double.tryParse(row['amount']?.toString() ?? '0') ?? 0; final balanceAfter = double.tryParse( row['balanceAfter']?.toString() ?? '0', ) ?? 0; final createdAt = DateTime.tryParse( row['createdAt']?.toString() ?? '', ); return ProfileWhiteCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( (row['description'] as String?) ?.isNotEmpty == true ? row['description'] as String : _kindLabel( locale, row['kind'] as String? ?? '', ), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: AppTheme.textPrimary, ), ), const SizedBox(height: 4), Text( createdAt != null ? '${createdAt.year}-${createdAt.month.toString().padLeft(2, '0')}-${createdAt.day.toString().padLeft(2, '0')} ${createdAt.hour.toString().padLeft(2, '0')}:${createdAt.minute.toString().padLeft(2, '0')}' : '—', style: const TextStyle( fontSize: 12, color: AppTheme.textSecondary, ), ), ], ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 5, ), decoration: BoxDecoration( color: isCredit ? AppTheme.success.withValues( alpha: 0.10, ) : AppTheme.danger.withValues( alpha: 0.10, ), borderRadius: BorderRadius.circular( AppTheme.chipRadius, ), ), child: Text( '${isCredit ? '+' : '-'}€${amount.toStringAsFixed(2)}', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w700, color: isCredit ? AppTheme.success : AppTheme.danger, ), ), ), ], ), const SizedBox(height: 10), Text( '${locale.t('profile.balanceHistory.after', 'Баланс после')}: €${balanceAfter.toStringAsFixed(2)}', style: const TextStyle( fontSize: 12, color: AppTheme.textSecondary, ), ), ], ), ); }, ), ), ); } }