import 'package:flutter/material.dart'; import '../../../extensions/date_time.dart'; import '../../../state/app/infrastructure/loadable_state/loadable_state.dart'; import '../../../state/app/infrastructure/loadable_state/view/loadable_state_consumer.dart'; import '../../../state/app/infrastructure/utility_widgets/bloc_module.dart'; import '../../../state/app/modules/marianum_dates/bloc/marianum_dates_bloc.dart'; import '../../../state/app/modules/marianum_dates/bloc/marianum_dates_event.dart'; import '../../../state/app/modules/marianum_dates/bloc/marianum_dates_state.dart'; import '../../../widget/placeholder_view.dart'; import 'search_marianum_dates.dart'; import 'widgets/event_list_tile.dart'; import 'widgets/month_section_header.dart'; class MarianumDatesView extends StatelessWidget { const MarianumDatesView({super.key}); /// Groups events by `yyyy-MM` (chronological). Uses the event's start date. static List<_MonthGroup> _groupByMonth(List events) { final byMonth = >{}; for (final e in events) { final key = '${e.start.year.toString().padLeft(4, '0')}-${e.start.month.toString().padLeft(2, '0')}'; byMonth.putIfAbsent(key, () => []).add(e); } final keys = byMonth.keys.toList()..sort(); return keys.map((key) { final first = byMonth[key]!.first.start; final label = first.formatMonthYear().toUpperCase(); return _MonthGroup(key: key, label: label, events: byMonth[key]!); }).toList(); } @override Widget build(BuildContext context) => BlocModule>( create: (context) => MarianumDatesBloc(), autoRebuild: true, child: (context, bloc, state) => Scaffold( appBar: AppBar( title: const Text('Marianum Termine'), actions: [ PopupMenuButton( initialValue: bloc.showPastEvents(), icon: const Icon(Icons.history), itemBuilder: (context) => [true, false] .map( (e) => PopupMenuItem( value: e, enabled: e != bloc.showPastEvents(), child: Row( children: [ Icon( e ? Icons.history_outlined : Icons.history_toggle_off_outlined, color: Theme.of(context).colorScheme.onSurface, ), const SizedBox(width: 15), Text( e ? 'Alle anzeigen' : 'Nur zukünftige anzeigen', ), ], ), ), ) .toList(), onSelected: (e) => bloc.add(SetPastEventsVisible(e)), ), IconButton( icon: const Icon(Icons.search), onPressed: () { final events = bloc.getEvents() ?? const []; showSearch( context: context, delegate: SearchMarianumDates(events), ); }, ), ], ), body: LoadableStateConsumer( child: (state, loading) { final events = bloc.getEvents() ?? const []; final groups = _groupByMonth(events); if (groups.isEmpty) { return const PlaceholderView( icon: Icons.event_busy_outlined, text: 'Keine Termine', ); } return CustomScrollView( slivers: [ for (final group in groups) SliverMainAxisGroup( slivers: [ SliverPersistentHeader( pinned: true, delegate: MonthHeaderDelegate(label: group.label), ), SliverList.builder( itemCount: group.events.length, itemBuilder: (_, i) => MarianumDateRow(event: group.events[i]), ), ], ), const SliverToBoxAdapter(child: SizedBox(height: 24)), ], ); }, ), ), ); } class _MonthGroup { final String key; final String label; final List events; _MonthGroup({required this.key, required this.label, required this.events}); }