import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../app/load_state.dart'; import '../models/event_log_item.dart'; import '../providers/providers.dart'; import '../widgets/load_error_view.dart'; /// Экран просмотра лога событий. class EventLogScreen extends ConsumerStatefulWidget { const EventLogScreen({super.key}); @override ConsumerState createState() => _EventLogScreenState(); } class _EventLogScreenState extends ConsumerState { int _limit = 100; @override void initState() { super.initState(); _load(); } Future _load() async { await ref.read(eventLogProvider.notifier).load(limit: _limit); } @override Widget build(BuildContext context) { final eventsState = ref.watch(eventLogProvider); final events = eventsState.data; return Scaffold( appBar: AppBar( title: const Text('ЛОГ СОБЫТИЙ'), actions: [ PopupMenuButton( icon: const Icon(Icons.filter_list), tooltip: 'Количество записей', onSelected: (v) { _limit = v; _load(); }, itemBuilder: (_) => [50, 100, 200, 500] .map((n) => PopupMenuItem(value: n, child: Text('$n записей'))) .toList(), ), ], ), body: _buildContent(eventsState, events), ); } Widget _buildContent( LoadState> eventsState, List events, ) { if ((eventsState.isIdle || eventsState.isLoading) && events.isEmpty) { return const Center( child: CircularProgressIndicator(color: Colors.deepOrange), ); } if (eventsState.hasError && events.isEmpty) { return LoadErrorView( title: 'Не удалось загрузить лог событий', message: eventsState.errorMessage, icon: Icons.list_alt, onRetry: _load, ); } if (events.isEmpty) { return const Center( child: Text('Нет событий', style: TextStyle(color: Colors.white54)), ); } final hasStatusHeader = eventsState.isLoading || eventsState.hasError; final statusHeaderCount = hasStatusHeader ? 1 : 0; return RefreshIndicator( color: Colors.deepOrange, onRefresh: _load, child: ListView.builder( physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.all(8), itemCount: events.length + statusHeaderCount, itemBuilder: (context, index) { if (hasStatusHeader && index == 0) { if (eventsState.isLoading) { return const Padding( padding: EdgeInsets.only(bottom: 12), child: LinearProgressIndicator(color: Colors.deepOrange), ); } return LoadErrorBanner( title: 'Не удалось обновить лог событий', message: eventsState.errorMessage, onRetry: _load, ); } final eventIndex = index - statusHeaderCount; return _EventRow(event: events[eventIndex]); }, ), ); } } class _EventRow extends StatelessWidget { final EventLogItem event; const _EventRow({required this.event}); @override Widget build(BuildContext context) { return Card( margin: const EdgeInsets.only(bottom: 4), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Время SizedBox( width: 80, child: Text( event.formattedTime, style: const TextStyle( fontSize: 11, color: Colors.white38, fontFamily: 'monospace', ), ), ), const SizedBox(width: 8), // Контент Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( event.title, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w500, ), ), if (event.paramsText.isNotEmpty) Text( event.paramsText, style: const TextStyle( fontSize: 11, color: Colors.white38, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), if (event.actor.isNotEmpty) Text( event.actor, style: const TextStyle( fontSize: 10, color: Colors.white24, ), ), ], ), ), ], ), ), ); } }