import 'package:ambito/src/domain/entity/massnahme/massnahme.dart'; import 'package:ambito/src/extensions/extensions.dart'; import 'package:ambito/src/packages/ambito_db/repositories/massnahme_repository.dart'; import 'package:ambito/src/widgets/form/fields/field_dropdown.dart'; import 'package:ambito/src/widgets/form/fields/field_monthsrangepicker.dart'; import 'package:ambito/src/widgets/form/form_widget.dart'; import 'package:ambito/src/widgets/form/form_widget_type.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:expandable_text/expandable_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import '../../../main.dart'; class ActionsPage extends StatefulWidget { const ActionsPage({super.key}); @override State createState() => ActionsPageState(); } class ActionsPageState extends State { Map visible = {}; List effort = []; List effect = []; Set type = {}; String? filterType; Set areaType = {}; String? filterAreaType; List region = []; String? filterSupport; Set support = {}; String? filterMonths; Set months = {}; List massnahmen = []; @override void initState() { super.initState(); massnahmen = MassnahmeRepository().getAll(); effort = []; effect = []; type = {}; areaType = {}; region = []; support = {}; } Widget build(BuildContext context) { // Step 1: Collect all distinct values in each Set in a single loop final updatedTypes = {}; final updatedAreaTypes = {}; final updatedSupports = {}; final updatedMonths = {}; for (final massnahme in massnahmen) { if (massnahme.actionGroup?.value != null) { updatedTypes.add(massnahme.actionGroup!.value!); } massnahme.factsheetAreaType?.forEach((aType) { updatedAreaTypes.add(aType.value!); }); massnahme.fundingPrograms?.forEach((aType) { updatedSupports.add(aType.value!); }); massnahme.timeFrame?.forEach((tfType) { updatedMonths.add(tfType.value!); }); } // Step 2: Update state with collected data in a single setState() call setState(() { type.addAll(updatedTypes); areaType.addAll(updatedAreaTypes); support.addAll(updatedSupports); months.addAll(updatedMonths); }); // Step 3: Generate the list of action cards with matching filters final actionCards = massnahmen.map((massnahme) { final typeMatches = filterType == null || massnahme.actionGroup?.value == filterType; final areaTypeMatches = filterAreaType == null || (massnahme.factsheetAreaType ?.any((aType) => aType.value == filterAreaType) ?? false); final supportMatches = filterSupport == null || (massnahme.fundingPrograms ?.any((aType) => aType.value == filterSupport) ?? false); // Update visibility in a single batch setState() setState(() { visible[massnahme.id] = typeMatches && areaTypeMatches && supportMatches; }); return getCard(context, massnahme); }).toList(); // Step 4: Return UI widget structure return Padding( padding: const EdgeInsets.symmetric(horizontal: 32), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( context.translate('page.actions.title'), style: Theme.of(context).textTheme.headlineLarge, ), getSpacer(), Text( context.translate('page.actions.intro'), style: Theme.of(context).textTheme.titleLarge, ), getSpacer(), Expanded( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(width: 300, child: getFilter(context)), const SizedBox(width: 16), Expanded( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: actionCards, ), ), ), ], ), ), getSpacer(), ], ), ); } Widget getSpacer() { return const SizedBox( height: 8, ); } Widget getFilter(BuildContext context) { List fields = []; fields.add( FieldDropdown( name: 'ort', label: 'Ort der Maßnahme', filterValue: filterAreaType, onClear: () { setState(() { filterAreaType = null; }); }, onSelected: ((String? value) { setState(() { filterAreaType = value; }); }), entries: areaType.toList(), ), ); fields.add( FieldDropdown( name: 'art', label: 'Art der Maßnahme', filterValue: filterType, onClear: () { setState(() { filterType = null; }); }, onSelected: ((String? value) { setState(() { filterType = value; }); }), entries: type.toList(), ), ); fields.add( FieldDropdown( name: 'support', label: 'Förderprogramm', filterValue: filterSupport, onClear: () { setState(() { filterSupport = null; }); }, onSelected: ((String? value) { setState(() { filterSupport = value; }); }), entries: support.toList(), ), ); List monthsSorted = []; for (int i = 1; i <= 12; i++) { monthsSorted .add(FlutterI18n.translate(context, 'general.lists.months.$i')); } fields.add( FieldMonthsRangepicker( name: 'months', label: 'Beginn der Maßnahme', filterValue: filterMonths, onClear: () {}, onSelected: (String? value) { logger.d(value); }, entries: monthsSorted, ), ); return FormWidget(type: FormWidgetType.vertical, fields: fields); } Widget getCard(BuildContext context, Massnahme massnahme) { final Map actionGroupColors = { 'Baulelemente': const Color(0xffFFD269), 'Begrünung': const Color(0xff40DD74), 'Bewirtschaftung': const Color(0xffBF72ED), 'Nisthilfe': const Color(0xffDAE3FD), 'Pflanzung': const Color(0xff40D6E9), 'Sondermaßnahmen': const Color(0xff689EF1), }; Color background = actionGroupColors[massnahme.actionGroup?.value] ?? Colors.white; CachedNetworkImage? image = massnahme.getThumbnail(); return Visibility( visible: visible[massnahme.id] ?? false, child: SizedBox( width: 800, child: Card( color: background, child: Padding( padding: const EdgeInsets.all(32), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ (image != null) ? image : const SizedBox( width: 300, height: 140, ), const SizedBox( width: 16, ), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(massnahme.name!, style: Theme.of(context).textTheme.headlineSmall), const SizedBox( height: 8, ), ExpandableText( massnahme.factsheetDefinition ?? '', maxLines: 3, expandText: 'mehr', collapseText: 'weniger', ) ], ), ) ], ), ), ), ), ); } }