import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'dart:developer' as dev; import '../../core/app_colors.dart'; import '../../di/service_locator.dart'; import '../../domain/entities/client_notification.dart'; import '../components/custom_app_bar.dart'; import '../event/notifications_event.dart'; import '../state/notifications_state.dart'; import '../viewmodel/notifications_bloc.dart'; enum NotificationFilter { all, auth, payment, order, } class NotificationsScreen extends StatelessWidget { const NotificationsScreen({super.key}); @override Widget build(BuildContext context) { return _NotificationsScreenContent(); } } class _NotificationsScreenContent extends StatefulWidget { const _NotificationsScreenContent(); @override State<_NotificationsScreenContent> createState() => _NotificationsScreenContentState(); } class _NotificationsScreenContentState extends State<_NotificationsScreenContent> { NotificationFilter _filter = NotificationFilter.all; void _setFilter(NotificationFilter filter) { setState(() { _filter = filter; }); } @override Widget build(BuildContext context) { return BlocProvider( create: (context) => getIt()..add(NotificationsFetchRequested()), child: NotificationsView( filter: _filter, onFilterChanged: _setFilter, ), ); } } class NotificationsView extends StatelessWidget { final NotificationFilter filter; final ValueChanged onFilterChanged; const NotificationsView({ super.key, this.filter = NotificationFilter.all, required this.onFilterChanged, }); @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: const BoxDecoration(gradient: AppColors.phoneScreenBg), child: SafeArea( child: Column( children: [ const SizedBox(height: 16), const Padding( padding: EdgeInsets.symmetric(horizontal: 20), child: CustomAppBar(title: 'Уведомления'), ), const SizedBox(height: 16), _buildFilterBar(), const SizedBox(height: 16), Expanded( child: BlocBuilder( builder: (context, state) { if (state.status == NotificationsStatus.loading) { return const Center(child: CircularProgressIndicator(color: Colors.white)); } if (state.status == NotificationsStatus.failure) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'Ошибка загрузки уведомлений', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 40), child: Text( state.errorMessage ?? '', style: TextStyle( color: Colors.white.withOpacity(0.6), fontSize: 14, ), textAlign: TextAlign.center, ), ), const SizedBox(height: 24), ElevatedButton( onPressed: () { context.read().add(NotificationsFetchRequested()); }, child: const Text('Повторить'), ), ], ), ); } final filtered = state.notifications.where((n) { switch (filter) { case NotificationFilter.all: return true; case NotificationFilter.auth: return n.category == NotificationCategory.auth; case NotificationFilter.payment: return n.category == NotificationCategory.payment; case NotificationFilter.order: return n.category == NotificationCategory.scooter; // || n.category == NotificationCategory.adminInfo // || n.category == NotificationCategory.companyInfo; default: return true; } }).toList(); if (filtered.isEmpty) { return const _EmptyState(); } return RefreshIndicator( onRefresh: () async { context.read().add(NotificationsFetchRequested()); }, child: ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 20), itemCount: filtered.length, itemBuilder: (context, index) { return _NotificationCard(notification: filtered[index]); }, ), ); }, ), ), ], ), ), ), ); } Widget _buildFilterBar() { final items = [ {'label': 'Все', 'value': NotificationFilter.all}, {'label': 'Авторизация', 'value': NotificationFilter.auth}, {'label': 'Оплата', 'value': NotificationFilter.payment}, {'label': 'Поездка', 'value': NotificationFilter.order}, ]; return Container( height: 40, padding: const EdgeInsets.symmetric(horizontal: 20), child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: items.map((item) { final isActive = item['value'] == filter; return Padding( padding: const EdgeInsets.only(right: 12), child: GestureDetector( onTap: () => onFilterChanged(item['value'] as NotificationFilter), child: Container( height: 32, padding: const EdgeInsets.symmetric(horizontal: 16), alignment: Alignment.center, decoration: BoxDecoration( gradient: isActive ? AppColors.activeButtonGradient : null, color: isActive ? null : Colors.transparent, borderRadius: BorderRadius.circular(20), border: Border.all( color: isActive ? Colors.transparent : Colors.white.withOpacity(0.4), width: 1, ), ), child: Text( item['label'] as String, textAlign: TextAlign.center, style: TextStyle( color: isActive ? AppColors.activeButtonText : Colors.white, fontSize: 14, fontWeight: isActive ? FontWeight.bold : FontWeight.normal, ), ), ), ), ); }).toList(), ), ), ); } } class _EmptyState extends StatelessWidget { const _EmptyState(); @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Image.asset( 'assets/notification_empty.png', width: 280, height: 280, fit: BoxFit.contain, errorBuilder: (context, error, stackTrace) { return const Icon( Icons.notifications_none_outlined, size: 120, color: Colors.white38, ); }, ), const SizedBox(height: 32), const Padding( padding: EdgeInsets.symmetric(horizontal: 40), child: Text( 'У вас пока нет уведомлений.', textAlign: TextAlign.center, style: TextStyle( color: Colors.white70, fontSize: 16, height: 1.5, ), ), ), ], ); } } class _NotificationCard extends StatelessWidget { final ClientNotification notification; const _NotificationCard({required this.notification}); @override Widget build(BuildContext context) { final date = _formatDate(notification.createdAt); return Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF141530).withOpacity(0.7), borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( date, style: TextStyle( color: Colors.white.withOpacity(0.6), fontSize: 12, ), ), const SizedBox(height: 8), Text( notification.content, style: const TextStyle( color: Colors.white, fontSize: 14, ), ), ], ), ); } String _formatDate(DateTime date) { final now = DateTime.now(); final difference = now.difference(date); if (difference.inDays == 0) { return 'Сегодня, ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}'; } else if (difference.inDays == 1) { return 'Вчера, ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}'; } else { return '${date.day.toString().padLeft(2, '0')}.${date.month.toString().padLeft(2, '0')}.${date.year}'; } } String _getTypeLabel(NotificationType type) { switch (type) { case NotificationType.info: return 'Информация'; case NotificationType.attention: return 'Внимание'; case NotificationType.warning: return 'Предупреждение'; } } String _getCategoryLabel(NotificationCategory category) { switch (category) { case NotificationCategory.auth: return 'Авторизация'; case NotificationCategory.zone: return 'Зоны'; case NotificationCategory.payment: return 'Оплата'; case NotificationCategory.companyInfo: return 'Акции'; case NotificationCategory.adminInfo: return 'Админ'; case NotificationCategory.scooter: return 'Самокат'; } } }