import 'package:flutter/material.dart'; import '../../../../api/connect/rmv/rmv_models.dart'; import '../../../../api/errors/error_mapper.dart'; import '../../../../extensions/date_time.dart'; import '../../../../state/app/modules/rmv/repository/rmv_repository.dart'; import '../../../../widget/app_progress_indicator.dart'; import '../../../../widget/details_bottom_sheet.dart'; class DisruptionsView extends StatefulWidget { const DisruptionsView({super.key}); @override State createState() => _DisruptionsViewState(); } class _DisruptionsViewState extends State { final RmvRepository _repo = RmvRepository(); List? _items; bool _loading = true; Object? _error; @override void initState() { super.initState(); _load(); } Future _load() async { setState(() { _loading = true; _error = null; }); try { final r = await _repo.disruptions(); if (!mounted) return; r.sort((a, b) => (b.priority ?? 0).compareTo(a.priority ?? 0)); setState(() { _items = r; _loading = false; }); } catch (e) { if (!mounted) return; setState(() { _error = e; _loading = false; }); } } @override Widget build(BuildContext context) => Scaffold( appBar: AppBar(title: const Text('Störungsmeldungen')), body: _body(), ); Widget _body() { if (_loading) return const Center(child: AppProgressIndicator.large()); final err = _error; if (err != null) { return Center( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( errorToUserMessage(err), textAlign: TextAlign.center, style: TextStyle(color: Theme.of(context).colorScheme.error), ), const SizedBox(height: 12), FilledButton.icon( icon: const Icon(Icons.refresh), onPressed: _load, label: const Text('Erneut versuchen'), ), ], ), ), ); } final list = _items ?? const []; if (list.isEmpty) { return RefreshIndicator( onRefresh: _load, child: ListView( physics: const AlwaysScrollableScrollPhysics(), children: const [ Padding( padding: EdgeInsets.symmetric(vertical: 80, horizontal: 24), child: Center(child: Text('Keine aktiven Meldungen.')), ), ], ), ); } return RefreshIndicator( onRefresh: _load, child: ListView.separated( itemCount: list.length, separatorBuilder: (_, _) => const Divider(height: 1), itemBuilder: (_, i) => _tile(list[i]), ), ); } Widget _tile(HimMessage msg) => ListTile( leading: Icon( Icons.warning_amber_outlined, color: _priorityColor(msg.priority), ), title: Text( msg.head ?? msg.lead ?? msg.text ?? 'Meldung', maxLines: 2, overflow: TextOverflow.ellipsis, ), subtitle: msg.lead == null ? null : Text(msg.lead!, maxLines: 2, overflow: TextOverflow.ellipsis), trailing: const Icon(Icons.chevron_right), onTap: () => _showDetails(msg), ); Color _priorityColor(int? priority) { if (priority == null) return Colors.orange; if (priority >= 100) return Colors.red; if (priority >= 50) return Colors.orange; return Colors.amber; } void _showDetails(HimMessage msg) { showDetailsBottomSheet( context, header: Padding( padding: const EdgeInsets.fromLTRB(16, 4, 16, 12), child: Text( msg.head ?? 'Störungsmeldung', style: Theme.of(context).textTheme.titleLarge, ), ), children: (ctx) => [ if (msg.lead != null) ListTile( leading: const Icon(Icons.short_text), title: Text(msg.lead!), ), if (msg.text != null) ListTile( leading: const Icon(Icons.notes), title: Text(msg.text!), ), if (msg.category != null) ListTile( leading: const Icon(Icons.category_outlined), title: Text(msg.category!), ), if (msg.company != null) ListTile( leading: const Icon(Icons.business_outlined), title: Text(msg.company!), ), if (msg.startValidity != null || msg.endValidity != null) ListTile( leading: const Icon(Icons.event_outlined), title: Text(_validityRange(msg)), ), if (msg.modified != null) ListTile( leading: const Icon(Icons.update_outlined), title: Text('Aktualisiert: ${msg.modified!.formatDateTime()}'), ), ], ); } String _validityRange(HimMessage msg) { final start = msg.startValidity?.formatDateTime(); final end = msg.endValidity?.formatDateTime(); if (start != null && end != null) return '$start – $end'; return start ?? end ?? ''; } }