import 'package:flutter/material.dart'; import '../api.dart'; import '../main.dart'; import 'ui.dart'; /// LT: manage the Wahlen of one KC — create, add workshops, run the /// assignment algorithm, view the result. class WahlAdminScreen extends StatefulWidget { const WahlAdminScreen({super.key, required this.kcId}); final String kcId; @override State createState() => _WahlAdminScreenState(); } class _WahlAdminScreenState extends State { Future>? _future; Api get _api => AppScope.of(context).api; @override void didChangeDependencies() { super.didChangeDependencies(); _future ??= _api.wahlenForKc(widget.kcId); } void _reload() => setState(() => _future = _api.wahlenForKc(widget.kcId)); Future _create() async { final api = _api; final v = await showDialog<(String, String, String)>( context: context, builder: (_) => const _NewWahlDialog(), ); if (v == null || !mounted) return; try { await api.createWahl(widget.kcId, v.$1, v.$2, v.$3); if (mounted) _reload(); } catch (e) { if (mounted) toast(context, '$e'); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Wahlen')), floatingActionButton: FloatingActionButton.extended( onPressed: _create, icon: const Icon(Icons.add), label: const Text('Wahl'), ), body: FutureBuilder>( future: _future, builder: (context, snap) { if (snap.connectionState != ConnectionState.done) { return const Center(child: CircularProgressIndicator()); } if (snap.hasError) return ErrorText('${snap.error}', onRetry: _reload); final wahlen = snap.data!; if (wahlen.isEmpty) { return const Center(child: Text('Noch keine Wahlen. Unten anlegen.')); } return ListView( children: [ for (final w in wahlen) ListTile( leading: Icon(w.isOpen ? Icons.lock_open : Icons.lock), title: Text(w.name), subtitle: Text('${w.datumsSchluessel} · Teil ${w.teil}'), trailing: const Icon(Icons.chevron_right), onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => WahlDetailScreen(wahl: w)), ), ), ], ); }, ), ); } } class WahlDetailScreen extends StatefulWidget { const WahlDetailScreen({super.key, required this.wahl}); final WahlAdmin wahl; @override State createState() => _WahlDetailScreenState(); } class _WahlDetailScreenState extends State { Future>? _workshops; Future>? _results; bool _running = false; Api get _api => AppScope.of(context).api; @override void didChangeDependencies() { super.didChangeDependencies(); _workshops ??= _api.workshopsForWahl(widget.wahl.id); _results ??= _api.zuteilungResults(widget.wahl.id); } void _reloadWorkshops() => setState(() => _workshops = _api.workshopsForWahl(widget.wahl.id)); void _reloadResults() => setState(() => _results = _api.zuteilungResults(widget.wahl.id)); Future _addWorkshop() async { final api = _api; final v = await showDialog<(String, int, int)>( context: context, builder: (_) => const _NewWorkshopDialog(), ); if (v == null || !mounted) return; try { await api.createWorkshop(widget.wahl.id, v.$1, v.$2, v.$3); if (mounted) _reloadWorkshops(); } catch (e) { if (mounted) toast(context, '$e'); } } Future _run() async { final api = _api; setState(() => _running = true); try { await api.runZuteilung(widget.wahl.id); if (mounted) _reloadResults(); } catch (e) { if (mounted) toast(context, '$e'); } finally { if (mounted) setState(() => _running = false); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.wahl.name)), body: ListView( padding: const EdgeInsets.all(16), children: [ SectionHeader('Workshops', action: TextButton.icon( onPressed: _addWorkshop, icon: const Icon(Icons.add), label: const Text('Hinzufügen'), )), FutureBuilder>( future: _workshops, builder: (context, snap) { if (snap.connectionState != ConnectionState.done) { return const LinearProgressIndicator(); } if (snap.hasError) return Text('Fehler: ${snap.error}'); final ws = snap.data!; if (ws.isEmpty) return const Text('Noch keine Workshops.'); return Column( children: [ for (final w in ws) ListTile( dense: true, leading: const Icon(Icons.groups), title: Text(w.name), subtitle: Text('Kapazität ${w.kapazitaet} · min. ${w.minTeilnehmer}'), ), ], ); }, ), const Divider(height: 40), Row( children: [ Expanded( child: Text('Zuteilung', style: Theme.of(context).textTheme.titleMedium), ), FilledButton.icon( onPressed: _running ? null : _run, icon: _running ? const SizedBox( height: 16, width: 16, child: CircularProgressIndicator(strokeWidth: 2)) : const Icon(Icons.play_arrow), label: const Text('Ausführen'), ), ], ), const SizedBox(height: 8), FutureBuilder>( future: _results, builder: (context, snap) { if (snap.connectionState != ConnectionState.done) { return const LinearProgressIndicator(); } if (snap.hasError) return Text('Fehler: ${snap.error}'); final rows = snap.data!; if (rows.isEmpty) { return const Text('Noch keine Zuteilung berechnet.'); } return Column( children: [ for (final r in rows) ListTile( dense: true, title: Text(r.name), subtitle: Text(r.workshopName ?? 'UNZUGETEILT'), trailing: Text( r.isForced ? 'fest' : r.wunschRang > 0 ? 'Wunsch ${r.wunschRang}' : '—', ), ), ], ); }, ), ], ), ); } } class _NewWahlDialog extends StatefulWidget { const _NewWahlDialog(); @override State<_NewWahlDialog> createState() => _NewWahlDialogState(); } class _NewWahlDialogState extends State<_NewWahlDialog> { final _name = TextEditingController(); final _datum = TextEditingController(); final _teil = TextEditingController(text: '1'); @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Neue Wahl'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField(controller: _name, decoration: const InputDecoration(labelText: 'Name')), TextField( controller: _datum, decoration: const InputDecoration(labelText: 'Datumsschlüssel (z. B. 2026-06-13)')), TextField(controller: _teil, decoration: const InputDecoration(labelText: 'Teil')), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Abbrechen')), FilledButton( onPressed: () => Navigator.of(context).pop( (_name.text.trim(), _datum.text.trim(), _teil.text.trim()), ), child: const Text('Anlegen'), ), ], ); } } class _NewWorkshopDialog extends StatefulWidget { const _NewWorkshopDialog(); @override State<_NewWorkshopDialog> createState() => _NewWorkshopDialogState(); } class _NewWorkshopDialogState extends State<_NewWorkshopDialog> { final _name = TextEditingController(); final _kap = TextEditingController(text: '12'); final _min = TextEditingController(text: '0'); @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Neuer Workshop'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField(controller: _name, decoration: const InputDecoration(labelText: 'Name')), TextField( controller: _kap, keyboardType: TextInputType.number, decoration: const InputDecoration(labelText: 'Kapazität')), TextField( controller: _min, keyboardType: TextInputType.number, decoration: const InputDecoration(labelText: 'Mindestteilnehmer')), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Abbrechen')), FilledButton( onPressed: () => Navigator.of(context).pop(( _name.text.trim(), int.tryParse(_kap.text) ?? 0, int.tryParse(_min.text) ?? 0, )), child: const Text('Anlegen'), ), ], ); } }