2024-10-07 11:01:02 +02:00
|
|
|
import 'package:ambito/src/extensions/extensions.dart';
|
2024-10-28 16:17:09 +01:00
|
|
|
import 'package:ambito/src/packages/ambito_db/repositories/measure_repository.dart';
|
2024-09-27 15:30:39 +02:00
|
|
|
import 'package:ambito/src/widgets/form/fields/field_dropdown.dart';
|
2024-09-27 15:40:55 +02:00
|
|
|
import 'package:ambito/src/widgets/form/fields/field_monthsrangepicker.dart';
|
2024-09-27 15:30:39 +02:00
|
|
|
import 'package:ambito/src/widgets/form/form_widget.dart';
|
|
|
|
import 'package:ambito/src/widgets/form/form_widget_type.dart';
|
2024-09-18 15:07:08 +02:00
|
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
|
|
|
import 'package:expandable_text/expandable_text.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
2024-10-09 01:14:07 +02:00
|
|
|
import 'package:flutter_i18n/flutter_i18n.dart';
|
2024-09-18 15:07:08 +02:00
|
|
|
|
|
|
|
import '../../../main.dart';
|
2024-10-28 16:17:09 +01:00
|
|
|
import '../../domain/entity/entities.dart';
|
2024-09-18 15:07:08 +02:00
|
|
|
|
|
|
|
class ActionsPage extends StatefulWidget {
|
2024-09-24 15:29:01 +02:00
|
|
|
const ActionsPage({super.key});
|
|
|
|
|
2024-09-18 15:07:08 +02:00
|
|
|
@override
|
|
|
|
State<StatefulWidget> createState() => ActionsPageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class ActionsPageState extends State<ActionsPage> {
|
|
|
|
Map<int, bool> visible = {};
|
|
|
|
List<String> effort = [];
|
|
|
|
List<String> effect = [];
|
2024-09-24 15:29:01 +02:00
|
|
|
Set<String> type = {};
|
2024-09-18 15:07:08 +02:00
|
|
|
String? filterType;
|
2024-09-24 15:29:01 +02:00
|
|
|
Set<String> areaType = {};
|
2024-09-18 15:07:08 +02:00
|
|
|
String? filterAreaType;
|
|
|
|
List<String> region = [];
|
2024-09-24 15:29:01 +02:00
|
|
|
String? filterSupport;
|
|
|
|
Set<String> support = {};
|
2024-09-27 15:30:39 +02:00
|
|
|
String? filterMonths;
|
|
|
|
Set<String> months = {};
|
2024-10-21 15:01:20 +02:00
|
|
|
List massnahmen = [];
|
2024-09-18 15:07:08 +02:00
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
2024-09-24 15:29:01 +02:00
|
|
|
super.initState();
|
2024-10-28 16:17:09 +01:00
|
|
|
massnahmen = MeasureRepository().getAll();
|
2024-09-18 15:07:08 +02:00
|
|
|
effort = [];
|
|
|
|
effect = [];
|
2024-09-24 15:29:01 +02:00
|
|
|
type = {};
|
|
|
|
areaType = {};
|
2024-09-18 15:07:08 +02:00
|
|
|
region = [];
|
2024-09-24 15:29:01 +02:00
|
|
|
support = {};
|
2024-09-18 15:07:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Widget build(BuildContext context) {
|
2024-10-21 15:01:20 +02:00
|
|
|
// Step 1: Collect all distinct values in each Set in a single loop
|
|
|
|
final updatedTypes = <String>{};
|
|
|
|
final updatedAreaTypes = <String>{};
|
|
|
|
final updatedSupports = <String>{};
|
|
|
|
final updatedMonths = <String>{};
|
2024-09-18 15:07:08 +02:00
|
|
|
|
2024-10-21 15:01:20 +02:00
|
|
|
for (final massnahme in massnahmen) {
|
|
|
|
if (massnahme.actionGroup?.value != null) {
|
2024-09-24 15:29:01 +02:00
|
|
|
updatedTypes.add(massnahme.actionGroup!.value!);
|
2024-09-18 15:07:08 +02:00
|
|
|
}
|
2024-09-24 15:29:01 +02:00
|
|
|
|
2024-10-21 15:01:20 +02:00
|
|
|
massnahme.factsheetAreaType?.forEach((aType) {
|
|
|
|
updatedAreaTypes.add(aType.value!);
|
|
|
|
});
|
|
|
|
|
|
|
|
massnahme.fundingPrograms?.forEach((aType) {
|
|
|
|
updatedSupports.add(aType.value!);
|
|
|
|
});
|
|
|
|
|
|
|
|
massnahme.timeFrame?.forEach((tfType) {
|
|
|
|
updatedMonths.add(tfType.value!);
|
|
|
|
});
|
|
|
|
}
|
2024-10-09 01:14:07 +02:00
|
|
|
|
2024-10-21 15:01:20 +02:00
|
|
|
// Step 2: Update state with collected data in a single setState() call
|
2024-09-24 15:29:01 +02:00
|
|
|
setState(() {
|
|
|
|
type.addAll(updatedTypes);
|
|
|
|
areaType.addAll(updatedAreaTypes);
|
|
|
|
support.addAll(updatedSupports);
|
2024-10-21 15:01:20 +02:00
|
|
|
months.addAll(updatedMonths);
|
2024-09-24 15:29:01 +02:00
|
|
|
});
|
|
|
|
|
2024-10-21 15:01:20 +02:00
|
|
|
// 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 ||
|
2024-09-24 15:29:01 +02:00
|
|
|
(massnahme.factsheetAreaType
|
|
|
|
?.any((aType) => aType.value == filterAreaType) ??
|
|
|
|
false);
|
2024-10-21 15:01:20 +02:00
|
|
|
final supportMatches = filterSupport == null ||
|
2024-09-24 15:29:01 +02:00
|
|
|
(massnahme.fundingPrograms
|
|
|
|
?.any((aType) => aType.value == filterSupport) ??
|
|
|
|
false);
|
|
|
|
|
2024-10-21 15:01:20 +02:00
|
|
|
// Update visibility in a single batch setState()
|
2024-09-18 15:07:08 +02:00
|
|
|
setState(() {
|
2024-09-24 15:29:01 +02:00
|
|
|
visible[massnahme.id] =
|
|
|
|
typeMatches && areaTypeMatches && supportMatches;
|
2024-09-18 15:07:08 +02:00
|
|
|
});
|
|
|
|
|
2024-09-24 15:29:01 +02:00
|
|
|
return getCard(context, massnahme);
|
|
|
|
}).toList();
|
2024-09-18 15:07:08 +02:00
|
|
|
|
2024-10-21 15:01:20 +02:00
|
|
|
// Step 4: Return UI widget structure
|
2024-09-18 15:07:08 +02:00
|
|
|
return Padding(
|
2024-10-21 15:01:20 +02:00
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 32),
|
2024-09-18 15:07:08 +02:00
|
|
|
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(
|
2024-10-09 01:14:07 +02:00
|
|
|
child: Row(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
2024-10-21 15:01:20 +02:00
|
|
|
SizedBox(width: 300, child: getFilter(context)),
|
|
|
|
const SizedBox(width: 16),
|
2024-10-09 01:14:07 +02:00
|
|
|
Expanded(
|
|
|
|
child: SingleChildScrollView(
|
2024-10-21 15:01:20 +02:00
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
2024-10-09 01:14:07 +02:00
|
|
|
children: actionCards,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
2024-09-18 15:07:08 +02:00
|
|
|
),
|
|
|
|
),
|
2024-10-09 01:14:07 +02:00
|
|
|
getSpacer(),
|
2024-09-18 15:07:08 +02:00
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget getSpacer() {
|
|
|
|
return const SizedBox(
|
|
|
|
height: 8,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget getFilter(BuildContext context) {
|
2024-09-27 15:30:39 +02:00
|
|
|
List<FormWidgetField> 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(),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
2024-10-09 01:14:07 +02:00
|
|
|
List<String> monthsSorted = [];
|
|
|
|
|
|
|
|
for (int i = 1; i <= 12; i++) {
|
|
|
|
monthsSorted
|
|
|
|
.add(FlutterI18n.translate(context, 'general.lists.months.$i'));
|
|
|
|
}
|
|
|
|
|
2024-09-27 15:30:39 +02:00
|
|
|
fields.add(
|
2024-09-27 15:40:55 +02:00
|
|
|
FieldMonthsRangepicker(
|
2024-09-27 15:30:39 +02:00
|
|
|
name: 'months',
|
|
|
|
label: 'Beginn der Maßnahme',
|
|
|
|
filterValue: filterMonths,
|
|
|
|
onClear: () {},
|
2024-10-21 15:01:20 +02:00
|
|
|
onSelected: (String? value) {
|
|
|
|
logger.d(value);
|
|
|
|
},
|
2024-10-09 01:14:07 +02:00
|
|
|
entries: monthsSorted,
|
2024-09-27 15:30:39 +02:00
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
return FormWidget(type: FormWidgetType.vertical, fields: fields);
|
2024-09-18 15:07:08 +02:00
|
|
|
}
|
|
|
|
|
2024-10-28 16:17:09 +01:00
|
|
|
Widget getCard(BuildContext context, Measure massnahme) {
|
2024-09-24 15:29:01 +02:00
|
|
|
final Map<String, Color> 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),
|
|
|
|
};
|
2024-09-18 15:07:08 +02:00
|
|
|
|
2024-09-24 15:29:01 +02:00
|
|
|
Color background =
|
|
|
|
actionGroupColors[massnahme.actionGroup?.value] ?? Colors.white;
|
|
|
|
|
|
|
|
CachedNetworkImage? image = massnahme.getThumbnail();
|
2024-09-18 15:07:08 +02:00
|
|
|
|
|
|
|
return Visibility(
|
|
|
|
visible: visible[massnahme.id] ?? false,
|
|
|
|
child: SizedBox(
|
2024-10-21 15:01:20 +02:00
|
|
|
width: 800,
|
2024-09-18 15:07:08 +02:00
|
|
|
child: Card(
|
|
|
|
color: background,
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.all(32),
|
2024-10-21 15:01:20 +02:00
|
|
|
child: Row(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
2024-09-18 15:07:08 +02:00
|
|
|
children: [
|
2024-10-21 15:01:20 +02:00
|
|
|
(image != null)
|
|
|
|
? image
|
|
|
|
: const SizedBox(
|
|
|
|
width: 300,
|
|
|
|
height: 140,
|
|
|
|
),
|
2024-09-18 15:07:08 +02:00
|
|
|
const SizedBox(
|
2024-10-21 15:01:20 +02:00
|
|
|
width: 16,
|
2024-09-18 15:07:08 +02:00
|
|
|
),
|
2024-10-21 15:01:20 +02:00
|
|
|
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',
|
|
|
|
)
|
|
|
|
],
|
|
|
|
),
|
2024-09-18 15:07:08 +02:00
|
|
|
)
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|