diff --git a/assets/i18n/de.json b/assets/i18n/de.json index f423c50..b9e5e72 100644 --- a/assets/i18n/de.json +++ b/assets/i18n/de.json @@ -1,32 +1,69 @@ { "page": { - "start": { + "general": { "title": "AmBiTo Toolkit", "links": { - "start": { - "title": "Start" - }, - "database": { + "massnahmen": { "title": "Maßnahmen" }, - "designer": { - "title": "Designer" + "dashboard": { + "title": "Dashboard" + } + }, + "spacer": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." + }, + "start": { + "links": { + "massnahmen": { + "title": "Maßnahmen" }, - "service": { - "title": "Beratung" - }, - "network": { - "title": "Netzwerk" - }, - "contact": { - "title": "Kontakt" + "dashboard": { + "title": "Dashboard" } } }, - "actions": { - "title": "Recherchieren Sie in allen Biodiversitätsmaßnahmen", - "intro": "In dieser Datenbank finden Sie die Maßnahmen, die zu Ihrem Betrieb und Ihrer Region passen." + "actionDetailPage": { + "description": { + "title": "Beschreibung" + }, + "background": { + "title": "Hintergrund", + "areaType": "Flächentyp", + "target": "Zielsetzung" + }, + "presets": { + "title": "Vorraussetzungen", + "tips": "Tipps" + }, + "biodiversity": { + "title": "Biodiversitätsbewertung" + }, + "creation":{ + "title": "Anlage", + "timeFrame": "Zeitrahmen" + }, + "maintenance": { + "title": "Pflege" + }, + "funding": { + "title": "Förderungen" + }, + "advisor": { + "title": "Ansprechpartner" + }, + "factsheet": { + "title": "Factsheet", + "download": "Download" + }, + "review": { + "title": "Rezensionen" + }, + "material": { + "title": "Material", + "suggested_price": "Preis ca. ", + "add_to_basket": "in den Warenkorb" + } } }, "general": { diff --git a/assets/images/actions/areatype/betriebsflaeche.jpg b/assets/images/actions/areatype/betriebsflaeche.jpg new file mode 100644 index 0000000..1e21ff8 Binary files /dev/null and b/assets/images/actions/areatype/betriebsflaeche.jpg differ diff --git a/assets/images/actions/areatype/betriebsstaette.jpg b/assets/images/actions/areatype/betriebsstaette.jpg new file mode 100644 index 0000000..7826dab Binary files /dev/null and b/assets/images/actions/areatype/betriebsstaette.jpg differ diff --git a/assets/images/actions/areatype/landschaft.jpg b/assets/images/actions/areatype/landschaft.jpg new file mode 100644 index 0000000..2745ca8 Binary files /dev/null and b/assets/images/actions/areatype/landschaft.jpg differ diff --git a/assets/images/actions/areatype/weinberg.jpg b/assets/images/actions/areatype/weinberg.jpg new file mode 100644 index 0000000..d6c14b6 Binary files /dev/null and b/assets/images/actions/areatype/weinberg.jpg differ diff --git a/lib/main.dart b/lib/main.dart index 2440930..1375d72 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,14 +1,21 @@ import 'package:ambito/src/packages/ambito_api/base_api.dart'; import 'package:ambito/src/packages/ambito_db/base_db.dart'; -import 'package:ambito/src/pages/loading/loading_page.dart'; +import 'package:ambito/src/packages/ambito_sharedprefs/ambito_sharedprefs.dart'; +import 'package:ambito/src/packages/ambito_theme/ambito_theme.dart'; +import 'package:ambito/src/pages/actions/action_detail_page.dart'; +import 'package:ambito/src/pages/actions/actions_page.dart'; +import 'package:ambito/src/pages/actions/actions_pre_page.dart'; +import 'package:ambito/src/pages/calendar/calendar_page.dart'; +import 'package:ambito/src/pages/calendar/calendar_page_year.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:get/get_navigation/src/root/get_material_app.dart'; +import 'package:get/get.dart'; import 'package:isar/isar.dart'; import 'package:logger/logger.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:syncfusion_localizations/syncfusion_localizations.dart'; final Logger logger = Logger( @@ -16,28 +23,31 @@ final Logger logger = Logger( ); late Isar isar; +late SharedPreferences prefs; +AmbitoTheme baseTheme = AmbitoTheme(); void main() async { WidgetsFlutterBinding.ensureInitialized(); await dotenv.load(fileName: '.env'); - - await AmbitoIsarDB().init(); - + await AmbitoSharedPrefs.start(); + await AmbitoIsarDB.init(); await Future.wait([ - /*BaseApi().getContent('tree_type'), + //BaseApi().getContent('tree_type'), BaseApi().getContent('measure'), BaseApi().getContent('measure_combination'), - BaseApi().getContent('organism'), - BaseApi().getContent('funding_program'), - BaseApi().getContent('location_requirements'), - BaseApi().getContent('reference_implementation'), - BaseApi().getContent('business'), - BaseApi().getContent('service_provider'), - BaseApi().getContent('service_provider_contact_person'), - BaseApi().getContent('material'),*/ - BaseApi().getContent('source'), + //BaseApi().getContent('organism'), + //BaseApi().getContent('funding_program'), + //BaseApi().getContent('location_requirements'), + //BaseApi().getContent('reference_implementation'), + //BaseApi().getContent('business'), + //BaseApi().getContent('service_provider'), + //BaseApi().getContent('service_provider_contact_person'), + //BaseApi().getContent('material'), + //BaseApi().getContent('source'), ]); + await MeasureRepository().buildMeasureFilters(); + runApp(const Ambito()); } @@ -64,15 +74,37 @@ class Ambito extends StatelessWidget { GlobalWidgetsLocalizations.delegate, SfGlobalLocalizations.delegate, ], - title: 'Flutter Demo', + title: 'AmBiTo', supportedLocales: const [Locale('de')], locale: const Locale('de'), builder: FlutterI18n.rootAppBuilder(), - theme: ThemeData( - scaffoldBackgroundColor: Colors.white, - useMaterial3: true, - ), - home: const LoadingPage(), + theme: baseTheme.lightThemeData, + darkTheme: baseTheme.darkThemeData, + themeMode: ThemeMode.light, + initialRoute: '/massnahmen', + getPages: [ + GetPage( + name: '/', + page: () => const ActionsPrePage(), + ), + GetPage( + name: '/kalender', + page: () => const CalendarPage(), + ), + GetPage( + name: '/kalender/jahr', + page: () => const CalendarPageYear(), + ), + GetPage( + name: '/massnahmen', + page: () => const ActionsPrePage(), + ), + GetPage( + name: '/massnahmendatenbank', + page: () => const ActionsPage(), + ), + GetPage(name: '/massnahme/:id', page: () => const ActionDetailPage()) + ], ); } } diff --git a/lib/src/entity/_general/filter/item_filter.dart b/lib/src/entity/_general/filter/item_filter.dart new file mode 100644 index 0000000..072c6d4 --- /dev/null +++ b/lib/src/entity/_general/filter/item_filter.dart @@ -0,0 +1,24 @@ +import 'package:ambito/src/entity/base_entity.dart'; +import 'package:isar/isar.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'item_filter.g.dart'; + +@collection +@JsonSerializable(explicitToJson: true) +class ItemFilter extends BaseEntity with EntityWithId { + ItemFilter(); + + String? type; + @Index(composite: ['type'], unique: true, hash: true) + String? name; + String? description; + String? image; + String? color; + List? ids = []; + + factory ItemFilter.fromJson(Map json) => + _$ItemFilterFromJson(json); + + Map toJson() => _$ItemFilterToJson(this); +} diff --git a/lib/src/entity/_general/filter/item_filter.g.dart b/lib/src/entity/_general/filter/item_filter.g.dart new file mode 100644 index 0000000..58a26ed --- /dev/null +++ b/lib/src/entity/_general/filter/item_filter.g.dart @@ -0,0 +1,1896 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'item_filter.dart'; + +// ************************************************************************** +// _IsarCollectionGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, invalid_use_of_protected_member, lines_longer_than_80_chars, constant_identifier_names, avoid_js_rounded_ints, no_leading_underscores_for_local_identifiers, require_trailing_commas, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_in_if_null_operators, library_private_types_in_public_api, prefer_const_constructors +// ignore_for_file: type=lint + +extension GetItemFilterCollection on Isar { + IsarCollection get itemFilters => this.collection(); +} + +const ItemFilterSchema = IsarGeneratedSchema( + schema: IsarSchema( + name: 'ItemFilter', + idName: 'id', + embedded: false, + properties: [ + IsarPropertySchema( + name: 'type', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'name', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'description', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'image', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'color', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'ids', + type: IsarType.longList, + ), + ], + indexes: [ + IsarIndexSchema( + name: 'name_type', + properties: [ + "name", + "type", + ], + unique: true, + hash: true, + ), + ], + ), + converter: IsarObjectConverter( + serialize: serializeItemFilter, + deserialize: deserializeItemFilter, + deserializeProperty: deserializeItemFilterProp, + ), + embeddedSchemas: [], +); + +@isarProtected +int serializeItemFilter(IsarWriter writer, ItemFilter object) { + { + final value = object.type; + if (value == null) { + IsarCore.writeNull(writer, 1); + } else { + IsarCore.writeString(writer, 1, value); + } + } + { + final value = object.name; + if (value == null) { + IsarCore.writeNull(writer, 2); + } else { + IsarCore.writeString(writer, 2, value); + } + } + { + final value = object.description; + if (value == null) { + IsarCore.writeNull(writer, 3); + } else { + IsarCore.writeString(writer, 3, value); + } + } + { + final value = object.image; + if (value == null) { + IsarCore.writeNull(writer, 4); + } else { + IsarCore.writeString(writer, 4, value); + } + } + { + final value = object.color; + if (value == null) { + IsarCore.writeNull(writer, 5); + } else { + IsarCore.writeString(writer, 5, value); + } + } + { + final list = object.ids; + if (list == null) { + IsarCore.writeNull(writer, 6); + } else { + final listWriter = IsarCore.beginList(writer, 6, list.length); + for (var i = 0; i < list.length; i++) { + IsarCore.writeLong(listWriter, i, list[i]); + } + IsarCore.endList(writer, listWriter); + } + } + return object.id; +} + +@isarProtected +ItemFilter deserializeItemFilter(IsarReader reader) { + final object = ItemFilter(); + object.type = IsarCore.readString(reader, 1); + object.name = IsarCore.readString(reader, 2); + object.description = IsarCore.readString(reader, 3); + object.image = IsarCore.readString(reader, 4); + object.color = IsarCore.readString(reader, 5); + { + final length = IsarCore.readList(reader, 6, IsarCore.readerPtrPtr); + { + final reader = IsarCore.readerPtr; + if (reader.isNull) { + object.ids = null; + } else { + final list = + List.filled(length, -9223372036854775808, growable: true); + for (var i = 0; i < length; i++) { + list[i] = IsarCore.readLong(reader, i); + } + IsarCore.freeReader(reader); + object.ids = list; + } + } + } + object.id = IsarCore.readId(reader); + return object; +} + +@isarProtected +dynamic deserializeItemFilterProp(IsarReader reader, int property) { + switch (property) { + case 1: + return IsarCore.readString(reader, 1); + case 2: + return IsarCore.readString(reader, 2); + case 3: + return IsarCore.readString(reader, 3); + case 4: + return IsarCore.readString(reader, 4); + case 5: + return IsarCore.readString(reader, 5); + case 6: + { + final length = IsarCore.readList(reader, 6, IsarCore.readerPtrPtr); + { + final reader = IsarCore.readerPtr; + if (reader.isNull) { + return null; + } else { + final list = + List.filled(length, -9223372036854775808, growable: true); + for (var i = 0; i < length; i++) { + list[i] = IsarCore.readLong(reader, i); + } + IsarCore.freeReader(reader); + return list; + } + } + } + case 0: + return IsarCore.readId(reader); + default: + throw ArgumentError('Unknown property: $property'); + } +} + +sealed class _ItemFilterUpdate { + bool call({ + required int id, + String? type, + String? name, + String? description, + String? image, + String? color, + }); +} + +class _ItemFilterUpdateImpl implements _ItemFilterUpdate { + const _ItemFilterUpdateImpl(this.collection); + + final IsarCollection collection; + + @override + bool call({ + required int id, + Object? type = ignore, + Object? name = ignore, + Object? description = ignore, + Object? image = ignore, + Object? color = ignore, + }) { + return collection.updateProperties([ + id + ], { + if (type != ignore) 1: type as String?, + if (name != ignore) 2: name as String?, + if (description != ignore) 3: description as String?, + if (image != ignore) 4: image as String?, + if (color != ignore) 5: color as String?, + }) > + 0; + } +} + +sealed class _ItemFilterUpdateAll { + int call({ + required List id, + String? type, + String? name, + String? description, + String? image, + String? color, + }); +} + +class _ItemFilterUpdateAllImpl implements _ItemFilterUpdateAll { + const _ItemFilterUpdateAllImpl(this.collection); + + final IsarCollection collection; + + @override + int call({ + required List id, + Object? type = ignore, + Object? name = ignore, + Object? description = ignore, + Object? image = ignore, + Object? color = ignore, + }) { + return collection.updateProperties(id, { + if (type != ignore) 1: type as String?, + if (name != ignore) 2: name as String?, + if (description != ignore) 3: description as String?, + if (image != ignore) 4: image as String?, + if (color != ignore) 5: color as String?, + }); + } +} + +extension ItemFilterUpdate on IsarCollection { + _ItemFilterUpdate get update => _ItemFilterUpdateImpl(this); + + _ItemFilterUpdateAll get updateAll => _ItemFilterUpdateAllImpl(this); +} + +sealed class _ItemFilterQueryUpdate { + int call({ + String? type, + String? name, + String? description, + String? image, + String? color, + }); +} + +class _ItemFilterQueryUpdateImpl implements _ItemFilterQueryUpdate { + const _ItemFilterQueryUpdateImpl(this.query, {this.limit}); + + final IsarQuery query; + final int? limit; + + @override + int call({ + Object? type = ignore, + Object? name = ignore, + Object? description = ignore, + Object? image = ignore, + Object? color = ignore, + }) { + return query.updateProperties(limit: limit, { + if (type != ignore) 1: type as String?, + if (name != ignore) 2: name as String?, + if (description != ignore) 3: description as String?, + if (image != ignore) 4: image as String?, + if (color != ignore) 5: color as String?, + }); + } +} + +extension ItemFilterQueryUpdate on IsarQuery { + _ItemFilterQueryUpdate get updateFirst => + _ItemFilterQueryUpdateImpl(this, limit: 1); + + _ItemFilterQueryUpdate get updateAll => _ItemFilterQueryUpdateImpl(this); +} + +class _ItemFilterQueryBuilderUpdateImpl implements _ItemFilterQueryUpdate { + const _ItemFilterQueryBuilderUpdateImpl(this.query, {this.limit}); + + final QueryBuilder query; + final int? limit; + + @override + int call({ + Object? type = ignore, + Object? name = ignore, + Object? description = ignore, + Object? image = ignore, + Object? color = ignore, + }) { + final q = query.build(); + try { + return q.updateProperties(limit: limit, { + if (type != ignore) 1: type as String?, + if (name != ignore) 2: name as String?, + if (description != ignore) 3: description as String?, + if (image != ignore) 4: image as String?, + if (color != ignore) 5: color as String?, + }); + } finally { + q.close(); + } + } +} + +extension ItemFilterQueryBuilderUpdate + on QueryBuilder { + _ItemFilterQueryUpdate get updateFirst => + _ItemFilterQueryBuilderUpdateImpl(this, limit: 1); + + _ItemFilterQueryUpdate get updateAll => + _ItemFilterQueryBuilderUpdateImpl(this); +} + +extension ItemFilterQueryFilter + on QueryBuilder { + QueryBuilder typeIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 1)); + }); + } + + QueryBuilder typeIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 1)); + }); + } + + QueryBuilder typeEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder typeGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + typeGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder typeLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + typeLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder typeBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 1, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder typeStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder typeEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder typeContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder typeMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 1, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder typeIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 1, + value: '', + ), + ); + }); + } + + QueryBuilder typeIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 1, + value: '', + ), + ); + }); + } + + QueryBuilder nameIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 2)); + }); + } + + QueryBuilder nameIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 2)); + }); + } + + QueryBuilder nameEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder nameGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + nameGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder nameLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + nameLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder nameBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 2, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder nameStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder nameEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder nameContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder nameMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 2, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder nameIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 2, + value: '', + ), + ); + }); + } + + QueryBuilder nameIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 2, + value: '', + ), + ); + }); + } + + QueryBuilder + descriptionIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 3)); + }); + } + + QueryBuilder + descriptionIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 3)); + }); + } + + QueryBuilder + descriptionEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 3, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 3, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 3, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 3, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 3, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 3, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 3, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 3, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 3, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 3, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + descriptionIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 3, + value: '', + ), + ); + }); + } + + QueryBuilder + descriptionIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 3, + value: '', + ), + ); + }); + } + + QueryBuilder imageIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 4)); + }); + } + + QueryBuilder imageIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 4)); + }); + } + + QueryBuilder imageEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imageGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + imageGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imageLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + imageLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imageBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 4, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imageStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imageEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imageContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imageMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 4, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imageIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 4, + value: '', + ), + ); + }); + } + + QueryBuilder + imageIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 4, + value: '', + ), + ); + }); + } + + QueryBuilder colorIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 5)); + }); + } + + QueryBuilder colorIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 5)); + }); + } + + QueryBuilder colorEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder colorGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + colorGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder colorLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + colorLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder colorBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 5, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder colorStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder colorEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder colorContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder colorMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 5, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder colorIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 5, + value: '', + ), + ); + }); + } + + QueryBuilder + colorIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 5, + value: '', + ), + ); + }); + } + + QueryBuilder idsIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 6)); + }); + } + + QueryBuilder idsIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 6)); + }); + } + + QueryBuilder idsElementEqualTo( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder + idsElementGreaterThan( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder + idsElementGreaterThanOrEqualTo( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder + idsElementLessThan( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder + idsElementLessThanOrEqualTo( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder idsElementBetween( + int lower, + int upper, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 6, + lower: lower, + upper: upper, + ), + ); + }); + } + + QueryBuilder idsIsEmpty() { + return not().group( + (q) => q.idsIsNull().or().idsIsNotEmpty(), + ); + } + + QueryBuilder idsIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterOrEqualCondition(property: 6, value: null), + ); + }); + } + + QueryBuilder idEqualTo( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 0, + value: value, + ), + ); + }); + } + + QueryBuilder idGreaterThan( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 0, + value: value, + ), + ); + }); + } + + QueryBuilder + idGreaterThanOrEqualTo( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 0, + value: value, + ), + ); + }); + } + + QueryBuilder idLessThan( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 0, + value: value, + ), + ); + }); + } + + QueryBuilder + idLessThanOrEqualTo( + int value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 0, + value: value, + ), + ); + }); + } + + QueryBuilder idBetween( + int lower, + int upper, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 0, + lower: lower, + upper: upper, + ), + ); + }); + } +} + +extension ItemFilterQueryObject + on QueryBuilder {} + +extension ItemFilterQuerySortBy + on QueryBuilder { + QueryBuilder sortByType( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 1, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByTypeDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 1, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 2, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByNameDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 2, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByDescription( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 3, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByDescriptionDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 3, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByImage( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 4, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByImageDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 4, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByColor( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 5, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByColorDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 5, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortById() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(0); + }); + } + + QueryBuilder sortByIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(0, sort: Sort.desc); + }); + } +} + +extension ItemFilterQuerySortThenBy + on QueryBuilder { + QueryBuilder thenByType( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(1, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByTypeDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(1, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(2, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByNameDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(2, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByDescription( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(3, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByDescriptionDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(3, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByImage( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(4, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByImageDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(4, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByColor( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(5, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByColorDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(5, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenById() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(0); + }); + } + + QueryBuilder thenByIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(0, sort: Sort.desc); + }); + } +} + +extension ItemFilterQueryWhereDistinct + on QueryBuilder { + QueryBuilder distinctByType( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(1, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(2, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByDescription( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(3, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByImage( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(4, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByColor( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(5, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByIds() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(6); + }); + } +} + +extension ItemFilterQueryProperty1 + on QueryBuilder { + QueryBuilder typeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(1); + }); + } + + QueryBuilder nameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(2); + }); + } + + QueryBuilder descriptionProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(3); + }); + } + + QueryBuilder imageProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(4); + }); + } + + QueryBuilder colorProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(5); + }); + } + + QueryBuilder?, QAfterProperty> idsProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(6); + }); + } + + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(0); + }); + } +} + +extension ItemFilterQueryProperty2 + on QueryBuilder { + QueryBuilder typeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(1); + }); + } + + QueryBuilder nameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(2); + }); + } + + QueryBuilder descriptionProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(3); + }); + } + + QueryBuilder imageProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(4); + }); + } + + QueryBuilder colorProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(5); + }); + } + + QueryBuilder?), QAfterProperty> idsProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(6); + }); + } + + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(0); + }); + } +} + +extension ItemFilterQueryProperty3 + on QueryBuilder { + QueryBuilder typeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(1); + }); + } + + QueryBuilder nameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(2); + }); + } + + QueryBuilder + descriptionProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(3); + }); + } + + QueryBuilder imageProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(4); + }); + } + + QueryBuilder colorProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(5); + }); + } + + QueryBuilder?), QOperations> idsProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(6); + }); + } + + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(0); + }); + } +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ItemFilter _$ItemFilterFromJson(Map json) => ItemFilter() + ..id = (json['id'] as num).toInt() + ..type = json['type'] as String? + ..name = json['name'] as String? + ..description = json['description'] as String? + ..image = json['image'] as String? + ..color = json['color'] as String? + ..ids = + (json['ids'] as List?)?.map((e) => (e as num).toInt()).toList(); + +Map _$ItemFilterToJson(ItemFilter instance) => + { + 'id': instance.id, + 'type': instance.type, + 'name': instance.name, + 'description': instance.description, + 'image': instance.image, + 'color': instance.color, + 'ids': instance.ids, + }; diff --git a/lib/src/entity/_general/filter/item_filter_repository.dart b/lib/src/entity/_general/filter/item_filter_repository.dart new file mode 100644 index 0000000..fd3dd2f --- /dev/null +++ b/lib/src/entity/_general/filter/item_filter_repository.dart @@ -0,0 +1,40 @@ +import 'package:ambito/src/entity/entities.dart'; +import 'package:ambito/src/packages/ambito_db/base_db.dart'; +import 'package:ambito/src/packages/ambito_notifier/notifier/filter_notifier.dart'; +import 'package:isar/isar.dart'; + +import '../../../../main.dart'; +import '../../../widgets/form/fields/field_dropdown.dart'; + +class ItemFilterRepository extends BaseDB { + @override + IsarCollection collection = isar.itemFilters; + + List? getByType(String type) { + return isar.itemFilters.where().typeEqualTo(type).findAll(); + } + + List? getIdsByType(String type) { + return isar.itemFilters + .where() + .typeEqualTo(type) + .idsProperty() + .findAll() + .expand((list) => list ?? []) + .toSet() + .toList(); + } + + FieldDropdown getDropDown(String type, String label) { + List filterItems = getByType(type)!; + + return FieldDropdown( + name: type, + label: label, + filterValue: ambitoFilterNotifier.activeFilters[type], + onClear: () => ambitoFilterNotifier.removeFilter(type), + onSelected: (value) => ambitoFilterNotifier.setFilter(type, value ?? ''), + entries: filterItems.map((item) => item.name!).toList(), + ); + } +} diff --git a/lib/src/entity/entities.dart b/lib/src/entity/entities.dart index 94c97fe..78246ef 100644 --- a/lib/src/entity/entities.dart +++ b/lib/src/entity/entities.dart @@ -3,6 +3,7 @@ library ambito_entities; export '_general/file/file_part.dart'; export '_general/file/thumbnail.dart'; export '_general/file/thumbnails.dart'; +export '_general/filter/item_filter.dart'; export '_general/id_value/id_value.dart'; export '_general/id_value_color/id_value_color.dart'; export '_general/id_value_mix/id_value_mix.dart'; diff --git a/lib/src/entity/measure/measure.dart b/lib/src/entity/measure/measure.dart index c4c8f1b..dbe98b6 100644 --- a/lib/src/entity/measure/measure.dart +++ b/lib/src/entity/measure/measure.dart @@ -51,7 +51,7 @@ class Measure extends BaseEntity with EntityWithId { @JsonKey(name: "Tipp - Anlage") String? attachmentTip; @JsonKey(name: "Zeitrahmen Pflege") - String? timeMaintenance; + List? timeMaintenance; @JsonKey(name: "Arbeitsschritte Pflege") String? workMaintenance; @JsonKey(name: "Frequenz Pflege") @@ -159,4 +159,20 @@ extension MeasureExtension on Measure { } return image; } + + CachedNetworkImage? getImage() { + CachedNetworkImage? image; + if (files != null && files!.isNotEmpty) { + if (files![0].thumbnails?.cardCover?.url != null) { + image = CachedNetworkImage( + width: 600, + height: 350, + imageUrl: files![0].thumbnails!.cardCover!.url!, + placeholder: (context, url) => const CircularProgressIndicator(), + errorWidget: (context, url, error) => const Icon(Icons.error), + ); + } + } + return image; + } } diff --git a/lib/src/entity/measure/measure.g.dart b/lib/src/entity/measure/measure.g.dart index b2fc449..5caa228 100644 --- a/lib/src/entity/measure/measure.g.dart +++ b/lib/src/entity/measure/measure.g.dart @@ -100,7 +100,8 @@ const MeasureSchema = IsarGeneratedSchema( ), IsarPropertySchema( name: 'timeMaintenance', - type: IsarType.string, + type: IsarType.objectList, + target: 'IdValueColor', ), IsarPropertySchema( name: 'workMaintenance', @@ -497,11 +498,20 @@ int serializeMeasure(IsarWriter writer, Measure object) { } } { - final value = object.timeMaintenance; - if (value == null) { + final list = object.timeMaintenance; + if (list == null) { IsarCore.writeNull(writer, 20); } else { - IsarCore.writeString(writer, 20, value); + final listWriter = IsarCore.beginList(writer, 20, list.length); + for (var i = 0; i < list.length; i++) { + { + final value = list[i]; + final objectWriter = IsarCore.beginObject(listWriter, i); + serializeIdValueColor(objectWriter, value); + IsarCore.endObject(listWriter, objectWriter); + } + } + IsarCore.endList(writer, listWriter); } } { @@ -1123,7 +1133,32 @@ Measure deserializeMeasure(IsarReader reader) { object.timeAction = IsarCore.readString(reader, 17); object.serviceProvider = IsarCore.readString(reader, 18); object.attachmentTip = IsarCore.readString(reader, 19); - object.timeMaintenance = IsarCore.readString(reader, 20); + { + final length = IsarCore.readList(reader, 20, IsarCore.readerPtrPtr); + { + final reader = IsarCore.readerPtr; + if (reader.isNull) { + object.timeMaintenance = null; + } else { + final list = + List.filled(length, IdValueColor(), growable: true); + for (var i = 0; i < length; i++) { + { + final objectReader = IsarCore.readObject(reader, i); + if (objectReader.isNull) { + list[i] = IdValueColor(); + } else { + final embedded = deserializeIdValueColor(objectReader); + IsarCore.freeReader(objectReader); + list[i] = embedded; + } + } + } + IsarCore.freeReader(reader); + object.timeMaintenance = list; + } + } + } object.workMaintenance = IsarCore.readString(reader, 21); { final length = IsarCore.readList(reader, 22, IsarCore.readerPtrPtr); @@ -1818,7 +1853,32 @@ dynamic deserializeMeasureProp(IsarReader reader, int property) { case 19: return IsarCore.readString(reader, 19); case 20: - return IsarCore.readString(reader, 20); + { + final length = IsarCore.readList(reader, 20, IsarCore.readerPtrPtr); + { + final reader = IsarCore.readerPtr; + if (reader.isNull) { + return null; + } else { + final list = List.filled(length, IdValueColor(), + growable: true); + for (var i = 0; i < length; i++) { + { + final objectReader = IsarCore.readObject(reader, i); + if (objectReader.isNull) { + list[i] = IdValueColor(); + } else { + final embedded = deserializeIdValueColor(objectReader); + IsarCore.freeReader(objectReader); + list[i] = embedded; + } + } + } + IsarCore.freeReader(reader); + return list; + } + } + } case 21: return IsarCore.readString(reader, 21); case 22: @@ -2497,7 +2557,6 @@ sealed class _MeasureUpdate { String? timeAction, String? serviceProvider, String? attachmentTip, - String? timeMaintenance, String? workMaintenance, String? specialsMaintenance, String? matchingActions, @@ -2546,7 +2605,6 @@ class _MeasureUpdateImpl implements _MeasureUpdate { Object? timeAction = ignore, Object? serviceProvider = ignore, Object? attachmentTip = ignore, - Object? timeMaintenance = ignore, Object? workMaintenance = ignore, Object? specialsMaintenance = ignore, Object? matchingActions = ignore, @@ -2590,7 +2648,6 @@ class _MeasureUpdateImpl implements _MeasureUpdate { if (timeAction != ignore) 17: timeAction as String?, if (serviceProvider != ignore) 18: serviceProvider as String?, if (attachmentTip != ignore) 19: attachmentTip as String?, - if (timeMaintenance != ignore) 20: timeMaintenance as String?, if (workMaintenance != ignore) 21: workMaintenance as String?, if (specialsMaintenance != ignore) 23: specialsMaintenance as String?, if (matchingActions != ignore) 24: matchingActions as String?, @@ -2643,7 +2700,6 @@ sealed class _MeasureUpdateAll { String? timeAction, String? serviceProvider, String? attachmentTip, - String? timeMaintenance, String? workMaintenance, String? specialsMaintenance, String? matchingActions, @@ -2692,7 +2748,6 @@ class _MeasureUpdateAllImpl implements _MeasureUpdateAll { Object? timeAction = ignore, Object? serviceProvider = ignore, Object? attachmentTip = ignore, - Object? timeMaintenance = ignore, Object? workMaintenance = ignore, Object? specialsMaintenance = ignore, Object? matchingActions = ignore, @@ -2734,7 +2789,6 @@ class _MeasureUpdateAllImpl implements _MeasureUpdateAll { if (timeAction != ignore) 17: timeAction as String?, if (serviceProvider != ignore) 18: serviceProvider as String?, if (attachmentTip != ignore) 19: attachmentTip as String?, - if (timeMaintenance != ignore) 20: timeMaintenance as String?, if (workMaintenance != ignore) 21: workMaintenance as String?, if (specialsMaintenance != ignore) 23: specialsMaintenance as String?, if (matchingActions != ignore) 24: matchingActions as String?, @@ -2788,7 +2842,6 @@ sealed class _MeasureQueryUpdate { String? timeAction, String? serviceProvider, String? attachmentTip, - String? timeMaintenance, String? workMaintenance, String? specialsMaintenance, String? matchingActions, @@ -2837,7 +2890,6 @@ class _MeasureQueryUpdateImpl implements _MeasureQueryUpdate { Object? timeAction = ignore, Object? serviceProvider = ignore, Object? attachmentTip = ignore, - Object? timeMaintenance = ignore, Object? workMaintenance = ignore, Object? specialsMaintenance = ignore, Object? matchingActions = ignore, @@ -2879,7 +2931,6 @@ class _MeasureQueryUpdateImpl implements _MeasureQueryUpdate { if (timeAction != ignore) 17: timeAction as String?, if (serviceProvider != ignore) 18: serviceProvider as String?, if (attachmentTip != ignore) 19: attachmentTip as String?, - if (timeMaintenance != ignore) 20: timeMaintenance as String?, if (workMaintenance != ignore) 21: workMaintenance as String?, if (specialsMaintenance != ignore) 23: specialsMaintenance as String?, if (matchingActions != ignore) 24: matchingActions as String?, @@ -2940,7 +2991,6 @@ class _MeasureQueryBuilderUpdateImpl implements _MeasureQueryUpdate { Object? timeAction = ignore, Object? serviceProvider = ignore, Object? attachmentTip = ignore, - Object? timeMaintenance = ignore, Object? workMaintenance = ignore, Object? specialsMaintenance = ignore, Object? matchingActions = ignore, @@ -2984,7 +3034,6 @@ class _MeasureQueryBuilderUpdateImpl implements _MeasureQueryUpdate { if (timeAction != ignore) 17: timeAction as String?, if (serviceProvider != ignore) 18: serviceProvider as String?, if (attachmentTip != ignore) 19: attachmentTip as String?, - if (timeMaintenance != ignore) 20: timeMaintenance as String?, if (workMaintenance != ignore) 21: workMaintenance as String?, if (specialsMaintenance != ignore) 23: specialsMaintenance as String?, if (matchingActions != ignore) 24: matchingActions as String?, @@ -6344,180 +6393,18 @@ extension MeasureQueryFilter }); } - QueryBuilder timeMaintenanceEqualTo( - String? value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - EqualCondition( - property: 20, - value: value, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder - timeMaintenanceGreaterThan( - String? value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - GreaterCondition( - property: 20, - value: value, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder - timeMaintenanceGreaterThanOrEqualTo( - String? value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - GreaterOrEqualCondition( - property: 20, - value: value, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder timeMaintenanceLessThan( - String? value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - LessCondition( - property: 20, - value: value, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder - timeMaintenanceLessThanOrEqualTo( - String? value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - LessOrEqualCondition( - property: 20, - value: value, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder timeMaintenanceBetween( - String? lower, - String? upper, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - BetweenCondition( - property: 20, - lower: lower, - upper: upper, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder - timeMaintenanceStartsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - StartsWithCondition( - property: 20, - value: value, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder timeMaintenanceEndsWith( - String value, { - bool caseSensitive = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - EndsWithCondition( - property: 20, - value: value, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder timeMaintenanceContains( - String value, - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - ContainsCondition( - property: 20, - value: value, - caseSensitive: caseSensitive, - ), - ); - }); - } - - QueryBuilder timeMaintenanceMatches( - String pattern, - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - MatchesCondition( - property: 20, - wildcard: pattern, - caseSensitive: caseSensitive, - ), - ); - }); - } - QueryBuilder timeMaintenanceIsEmpty() { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition( - const EqualCondition( - property: 20, - value: '', - ), - ); - }); + return not().group( + (q) => q.timeMaintenanceIsNull().or().timeMaintenanceIsNotEmpty(), + ); } QueryBuilder timeMaintenanceIsNotEmpty() { return QueryBuilder.apply(this, (query) { return query.addFilterCondition( - const GreaterCondition( - property: 20, - value: '', - ), + const GreaterOrEqualCondition(property: 20, value: null), ); }); } @@ -11325,27 +11212,6 @@ extension MeasureQuerySortBy on QueryBuilder { }); } - QueryBuilder sortByTimeMaintenance( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addSortBy( - 20, - caseSensitive: caseSensitive, - ); - }); - } - - QueryBuilder sortByTimeMaintenanceDesc( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addSortBy( - 20, - sort: Sort.desc, - caseSensitive: caseSensitive, - ); - }); - } - QueryBuilder sortByWorkMaintenance( {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { @@ -12010,20 +11876,6 @@ extension MeasureQuerySortThenBy }); } - QueryBuilder thenByTimeMaintenance( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(20, caseSensitive: caseSensitive); - }); - } - - QueryBuilder thenByTimeMaintenanceDesc( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(20, sort: Sort.desc, caseSensitive: caseSensitive); - }); - } - QueryBuilder thenByWorkMaintenance( {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { @@ -12436,13 +12288,6 @@ extension MeasureQueryWhereDistinct }); } - QueryBuilder distinctByTimeMaintenance( - {bool caseSensitive = true}) { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(20, caseSensitive: caseSensitive); - }); - } - QueryBuilder distinctByWorkMaintenance( {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { @@ -12702,7 +12547,8 @@ extension MeasureQueryProperty1 on QueryBuilder { }); } - QueryBuilder timeMaintenanceProperty() { + QueryBuilder?, QAfterProperty> + timeMaintenanceProperty() { return QueryBuilder.apply(this, (query) { return query.addProperty(20); }); @@ -13126,7 +12972,7 @@ extension MeasureQueryProperty2 on QueryBuilder { }); } - QueryBuilder + QueryBuilder?), QAfterProperty> timeMaintenanceProperty() { return QueryBuilder.apply(this, (query) { return query.addProperty(20); @@ -13564,7 +13410,7 @@ extension MeasureQueryProperty3 }); } - QueryBuilder + QueryBuilder?), QOperations> timeMaintenanceProperty() { return QueryBuilder.apply(this, (query) { return query.addProperty(20); @@ -13907,7 +13753,9 @@ Measure _$MeasureFromJson(Map json) => Measure() ..timeAction = json['Fachgerechte Umsetzung_Anlage_Kosten_Zeit'] as String? ..serviceProvider = json['Dienstleister redundant'] as String? ..attachmentTip = json['Tipp - Anlage'] as String? - ..timeMaintenance = json['Zeitrahmen Pflege'] as String? + ..timeMaintenance = (json['Zeitrahmen Pflege'] as List?) + ?.map((e) => IdValueColor.fromJson(e as Map)) + .toList() ..workMaintenance = json['Arbeitsschritte Pflege'] as String? ..frequencyMaintenance = (json['Frequenz Pflege'] as List?) ?.map((e) => IdValueColor.fromJson(e as Map)) @@ -14025,7 +13873,8 @@ Map _$MeasureToJson(Measure instance) => { 'Fachgerechte Umsetzung_Anlage_Kosten_Zeit': instance.timeAction, 'Dienstleister redundant': instance.serviceProvider, 'Tipp - Anlage': instance.attachmentTip, - 'Zeitrahmen Pflege': instance.timeMaintenance, + 'Zeitrahmen Pflege': + instance.timeMaintenance?.map((e) => e.toJson()).toList(), 'Arbeitsschritte Pflege': instance.workMaintenance, 'Frequenz Pflege': instance.frequencyMaintenance?.map((e) => e.toJson()).toList(), diff --git a/lib/src/entity/measure/measure_repository.dart b/lib/src/entity/measure/measure_repository.dart index a69a08e..a92d3c5 100644 --- a/lib/src/entity/measure/measure_repository.dart +++ b/lib/src/entity/measure/measure_repository.dart @@ -1,4 +1,6 @@ +import 'package:ambito/src/entity/_general/filter/item_filter_repository.dart'; import 'package:ambito/src/entity/entities.dart'; +import 'package:ambito/src/extensions/extensions.dart'; import 'package:ambito/src/packages/ambito_db/base_db.dart'; import 'package:isar/isar.dart'; @@ -7,4 +9,96 @@ import '../../../../main.dart'; class MeasureRepository extends BaseDB { @override IsarCollection collection = isar.measures; + + Future buildMeasureFilters() async { + Map> filtersAreaType = {}; + Map> filtersMeasureGroup = {}; + Map> filterMonths = {}; + Map> filterFundingPrograms = {}; + Map colors = {}; + + var measures = getAll(); + + for (Measure measure in measures) { + measure.factsheetAreaType?.forEach((ivc) { + filtersAreaType.putIfAbsent(ivc.value!, () => []).add(measure.id); + colors[ivc.value!] = ivc.color!; + }); + + if (measure.actionGroup != null) { + filtersMeasureGroup + .putIfAbsent(measure.actionGroup!.value!, () => []) + .add(measure.id); + colors[measure.actionGroup!.value!] = measure.actionGroup!.color!; + } + + measure.timeFrame?.forEach((ivc) { + filterMonths.putIfAbsent(ivc.value!, () => []).add(measure.id); + colors[ivc.value!] = ivc.color!; + }); + + measure.fundingPrograms?.forEach((ivc) { + filterFundingPrograms.putIfAbsent(ivc.value!, () => []).add(measure.id); + }); + } + + final itemFilterRepo = ItemFilterRepository(); + final autoIncrement = isar.itemFilters.autoIncrement; + + itemFilterRepo.putAll(filtersAreaType.entries + .map((entry) => ItemFilter() + ..id = autoIncrement() + ..name = entry.key + ..type = 'areaType' + ..description = + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.' + ..image = + 'images/actions/areatype/${entry.key.toLowerCase().replaceUmlauts()}.jpg' + ..color = colors[entry.key] + ..ids = entry.value) + .toList()); + + itemFilterRepo.putAll(filtersMeasureGroup.entries + .map((entry) => ItemFilter() + ..id = autoIncrement() + ..name = entry.key + ..type = 'group' + ..description = + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.' + ..image = + 'images/actions/areatype/${entry.key.toLowerCase().replaceUmlauts()}.jpg' + ..color = colors[entry.key] + ..ids = entry.value) + .toList()); + + itemFilterRepo.putAll(filterMonths.entries + .map((entry) => ItemFilter() + ..id = autoIncrement() + ..name = entry.key + ..type = 'month' + ..ids = entry.value) + .toList()); + + itemFilterRepo.putAll(filterFundingPrograms.entries + .map((entry) => ItemFilter() + ..id = autoIncrement() + ..name = entry.key + ..type = 'fundingProgram' + ..ids = entry.value) + .toList()); + + return true; + } + + int getMeasureCount() { + return isar.measures.where().count(); + } + + List getByIds(List ids) { + return isar.measures.getAll(ids); + } + + List getAllOrdered() { + return isar.measures.where().sortByName().findAll(); + } } diff --git a/lib/src/extensions/datetime_extensions.dart b/lib/src/extensions/datetime_extensions.dart index 512177b..0e8bb9a 100644 --- a/lib/src/extensions/datetime_extensions.dart +++ b/lib/src/extensions/datetime_extensions.dart @@ -68,4 +68,7 @@ extension DateHelpers on DateTime { DateTime lastDayOfYear() { return DateTime(year + 1, 1, 0); } + + DateTime get lastDayOfMonth => + month < 12 ? DateTime(year, month + 1, 0) : DateTime(year + 1, 1, 0); } diff --git a/lib/src/extensions/extensions.dart b/lib/src/extensions/extensions.dart index ddee7ce..b32d14e 100644 --- a/lib/src/extensions/extensions.dart +++ b/lib/src/extensions/extensions.dart @@ -5,3 +5,4 @@ import 'package:flutter_i18n/flutter_i18n.dart'; part 'datetime_extensions.dart'; part 'i18n_extensions.dart'; +part 'string_extensions.dart'; diff --git a/lib/src/extensions/string_extensions.dart b/lib/src/extensions/string_extensions.dart new file mode 100644 index 0000000..6ebdde8 --- /dev/null +++ b/lib/src/extensions/string_extensions.dart @@ -0,0 +1,23 @@ +part of 'extensions.dart'; + +extension StringExtensions on String { + replaceUmlauts() { + return replaceAll("ü", "ue") + .replaceAll("ö", "oe") + .replaceAll("ä", "ae") + .replaceAll("ß", "ss") + .replaceAll("Ü(?=[a-zäöüß ])", "Ue") + .replaceAll("Ö(?=[a-zäöüß ])", "Oe") + .replaceAll("Ä(?=[a-zäöüß ])", "Ae") + .replaceAll("Ü", "UE") + .replaceAll("Ö", "OE") + .replaceAll("Ä", "AE"); + } + + Color hexToColor() { + final buffer = StringBuffer(); + if (length == 6 || length == 7) buffer.write('ff'); + buffer.write(replaceFirst('#', '')); + return Color(int.parse(buffer.toString(), radix: 16)); + } +} diff --git a/lib/src/packages/ambito_api/base_api.dart b/lib/src/packages/ambito_api/base_api.dart index 66dacb1..174301b 100644 --- a/lib/src/packages/ambito_api/base_api.dart +++ b/lib/src/packages/ambito_api/base_api.dart @@ -4,7 +4,6 @@ import 'package:ambito/src/entity/entities.dart'; import 'package:ambito/src/packages/ambito_api/restclient.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; -import '../../../main.dart'; import '../ambito_db/base_db.dart'; class BaseApi { @@ -27,9 +26,9 @@ class BaseApi { var json = _jsonDecoded(response.body); - if (table == 'source') { - logger.d(json); - } + //if (table == 'measure') { + //logger.d(json); + //} var results = json['results']; diff --git a/lib/src/packages/ambito_db/base_db.dart b/lib/src/packages/ambito_db/base_db.dart index 8414324..9a2cc03 100644 --- a/lib/src/packages/ambito_db/base_db.dart +++ b/lib/src/packages/ambito_db/base_db.dart @@ -1,4 +1,3 @@ -import 'package:ambito/src/entity/approval_requirement/approval_requirement.dart'; import 'package:ambito/src/entity/entities.dart'; import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; @@ -9,7 +8,7 @@ import '../../../main.dart'; export 'repositories/_repositories.dart'; class AmbitoIsarDB { - init() async { + static init() async { await Isar.initialize(); String dir = kIsWeb ? Isar.sqliteInMemory @@ -19,8 +18,11 @@ class AmbitoIsarDB { schemas: [ ApprovalRequirementSchema, BusinessSchema, + ExperienceReportSchema, FundingProgramSchema, + ItemFilterSchema, LocationRequirementsSchema, + MaterialSchema, MeasureSchema, MeasureCombinationSchema, NumberFactsheetSchema, diff --git a/lib/src/packages/ambito_notifier/ambito_notifier.dart b/lib/src/packages/ambito_notifier/ambito_notifier.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/packages/ambito_notifier/notifier/filter_notifier.dart b/lib/src/packages/ambito_notifier/notifier/filter_notifier.dart new file mode 100644 index 0000000..3b3b752 --- /dev/null +++ b/lib/src/packages/ambito_notifier/notifier/filter_notifier.dart @@ -0,0 +1,38 @@ +import 'package:ambito/main.dart'; +import 'package:ambito/src/entity/_general/filter/item_filter_repository.dart'; +import 'package:flutter/cupertino.dart'; + +AmbitoFilterNotifier ambitoFilterNotifier = AmbitoFilterNotifier(); + +class AmbitoFilterNotifier extends ChangeNotifier { + AmbitoFilterNotifier(); + + AmbitoFilterNotifier.create(BuildContext context); + + Map activeFilters = {}; + Map?> activeIds = {}; + + List mergedIds = []; + + void setFilter(String type, String value) { + prefs.setString('filter_$type', value).then((_) { + activeFilters[type] = value; + activeIds[type] = ItemFilterRepository().getIdsByType(type); + notifyListeners(); + }); + } + + void removeFilter(String type) { + prefs.remove('filter_$type').then((_) { + activeFilters[type] = null; + activeIds[type] = null; + notifyListeners(); + }); + } + + List? getMergedIds() {} + + String? getFilter(String type) { + return activeFilters[type]; + } +} diff --git a/lib/src/packages/ambito_sharedprefs/ambito_sharedprefs.dart b/lib/src/packages/ambito_sharedprefs/ambito_sharedprefs.dart new file mode 100644 index 0000000..d588b5f --- /dev/null +++ b/lib/src/packages/ambito_sharedprefs/ambito_sharedprefs.dart @@ -0,0 +1,10 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../../main.dart'; + +class AmbitoSharedPrefs { + static Future start() async { + prefs = await SharedPreferences.getInstance(); + return prefs; + } +} diff --git a/lib/src/packages/ambito_theme/ambito_theme.dart b/lib/src/packages/ambito_theme/ambito_theme.dart new file mode 100644 index 0000000..5112f30 --- /dev/null +++ b/lib/src/packages/ambito_theme/ambito_theme.dart @@ -0,0 +1,237 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +final actionGroupColors = { + 'Bauelemente': const Color(0xffFFD269).withOpacity(.4), + 'Begrünung': const Color(0xff40DD74).withOpacity(.4), + 'Bewirtschaftung': const Color(0xffBF72ED).withOpacity(.4), + 'Nisthilfe': const Color(0xffDAE3FD).withOpacity(.4), + 'Pflanzung': const Color(0xff40D6E9).withOpacity(.4), + 'Sondermaßnahmen': const Color(0xff689EF1).withOpacity(.4), +}; + +final actionAreaColors = { + 'Landschaft': const Color(0xfff8e0aa).withOpacity(.6), + 'Weinberg': const Color(0xffacc11e).withOpacity(.6), + 'Betriebsfläche': const Color(0xffca414c).withOpacity(.6), + 'Betriebsstätte': const Color(0xffCCCDCC).withOpacity(.6), +}; + +final actionAreaFGColors = { + 'Landschaft': const Color(0xffec863a), + 'Weinberg': const Color(0xff3d693f), + 'Betriebsfläche': const Color(0xff883443), + 'Betriebsstätte': const Color(0xff999999), +}; + +class AmbitoTheme { + static ThemeMode appThemeMode = ThemeMode.light; + + ColorScheme get lightColorScheme => const ColorScheme( + brightness: Brightness.light, + primary: Color(0xFF60845E), + onPrimary: Color(0xFFFFFFFF), + primaryContainer: Color(0xFFDCE3C9), + onPrimaryContainer: Color(0xFF001E2D), + secondary: Color(0xFFF5F5F5), + onSecondary: Color(0xFFFFFFFF), + secondaryContainer: Color(0xFFD2E5F4), + onSecondaryContainer: Color(0xFF0A1D28), + tertiary: Color(0xFFD9D9D9), + onTertiary: Color(0xFFFFFFFF), + tertiaryContainer: Color(0xFFB8F483), + onTertiaryContainer: Color(0xFF0D2000), + error: Color(0xFFBA1A1A), + errorContainer: Color(0xFFFFDAD6), + onError: Color(0xFFFFFFFF), + onErrorContainer: Color(0xFF410002), + surface: Color(0xFFffffff), + onSurface: Color(0xFF656565), + surfaceContainerHighest: Color(0xFFDDE3EA), + onSurfaceVariant: Color(0xFF41484D), + outline: Color(0xFF71787E), + onInverseSurface: Color(0xFFF0F1F3), + inverseSurface: Color(0xFF2E3133), + inversePrimary: Color(0xFF82CFFF), + shadow: Color(0xFF000000), + surfaceTint: Color(0xFF00658D), + outlineVariant: Color(0xFFC1C7CE), + scrim: Color(0xFF000000), + ); + + ColorScheme get darkColorScheme => const ColorScheme( + brightness: Brightness.dark, + primary: Color(0xFF82CFFF), + onPrimary: Color(0xFF00344B), + primaryContainer: Color(0xFF004C6B), + onPrimaryContainer: Color(0xFFC6E7FF), + secondary: Color(0xFFB6C9D8), + onSecondary: Color(0xFF21323E), + secondaryContainer: Color(0xFF374955), + onSecondaryContainer: Color(0xFFD2E5F4), + tertiary: Color(0xFF9DD76A), + onTertiary: Color(0xFF1A3700), + tertiaryContainer: Color(0xFF285000), + onTertiaryContainer: Color(0xFFB8F483), + error: Color(0xFFFFB4AB), + errorContainer: Color(0xFF93000A), + onError: Color(0xFF690005), + onErrorContainer: Color(0xFFFFDAD6), + surface: Color(0xFF191C1E), + onSurface: Color(0xFFE2E2E5), + surfaceContainerHighest: Color(0xFF41484D), + onSurfaceVariant: Color(0xFFC1C7CE), + outline: Color(0xFF8B9198), + onInverseSurface: Color(0xFF191C1E), + inverseSurface: Color(0xFFE2E2E5), + inversePrimary: Color(0xFF00658D), + shadow: Color(0xFF000000), + surfaceTint: Color(0xFF82CFFF), + outlineVariant: Color(0xFF41484D), + scrim: Color(0xFF000000), + ); + + TextStyle get defaultFont => GoogleFonts.roboto(); + TextStyle get displayLarge => textTheme.displayLarge!; + TextStyle get displayMedium => textTheme.displayMedium!; + TextStyle get displaySmall => textTheme.displaySmall!; + TextStyle get headlineLarge => textTheme.headlineLarge!; + TextStyle get headlineMedium => textTheme.headlineMedium!; + TextStyle get headlineSmall => textTheme.headlineSmall!; + TextStyle get titleLarge => textTheme.titleLarge!; + TextStyle get titleMedium => textTheme.titleMedium!; + TextStyle get titleSmall => textTheme.titleSmall!; + TextStyle get labelLarge => textTheme.labelLarge!; + TextStyle get labelMedium => textTheme.labelMedium!; + TextStyle get labelSmall => textTheme.labelSmall!; + TextStyle get bodyLarge => textTheme.bodyLarge!; + TextStyle get bodyMedium => textTheme.bodyMedium!; + TextStyle get bodySmall => textTheme.bodySmall!; + + TextTheme get textTheme => TextTheme( + displayLarge: GoogleFonts.openSans( + fontSize: 57, + height: 1.12, + fontWeight: FontWeight.w400, + letterSpacing: -.25), + displayMedium: GoogleFonts.openSans( + fontSize: 45, + height: 1.15, + fontWeight: FontWeight.w400, + letterSpacing: 0, + ), + displaySmall: GoogleFonts.openSans( + fontSize: 36, + height: 1.22, + fontWeight: FontWeight.w400, + letterSpacing: 0, + ), + headlineLarge: GoogleFonts.openSans( + fontSize: 44, + height: 1.25, + fontWeight: FontWeight.w400, + letterSpacing: 0, + ), + headlineMedium: GoogleFonts.openSans( + fontSize: 28, + height: 1.29, + fontWeight: FontWeight.w400, + letterSpacing: 0, + ), + headlineSmall: GoogleFonts.openSans( + fontSize: 24, + height: 1.33, + fontWeight: FontWeight.w400, + letterSpacing: 0, + ), + titleLarge: GoogleFonts.openSans( + fontSize: 22, + height: 1.27, + fontWeight: FontWeight.w400, + letterSpacing: 0, + ), + titleMedium: GoogleFonts.openSans( + fontSize: 16, + height: 1.5, + fontWeight: FontWeight.w500, + letterSpacing: 0.15, + ), + titleSmall: GoogleFonts.openSans( + fontSize: 14, + height: 1.42, + fontWeight: FontWeight.w500, + letterSpacing: 0.1, + ), + labelLarge: GoogleFonts.openSans( + fontSize: 14, + height: 1.42, + fontWeight: FontWeight.w500, + letterSpacing: 0.1, + ), + labelMedium: GoogleFonts.openSans( + fontSize: 12, + height: 1.33, + fontWeight: FontWeight.w500, + letterSpacing: 0.15, + ), + labelSmall: GoogleFonts.openSans( + fontSize: 11, + height: 1.45, + fontWeight: FontWeight.w500, + letterSpacing: 0.1, + ), + bodyLarge: GoogleFonts.openSans( + fontSize: 16, + height: 1.5, + fontWeight: FontWeight.w400, + letterSpacing: 0.5, + ), + bodyMedium: GoogleFonts.openSans( + fontSize: 14, + height: 1.42, + fontWeight: FontWeight.w400, + letterSpacing: 0.25, + ), + bodySmall: GoogleFonts.openSans( + fontSize: 12, + height: 1.33, + fontWeight: FontWeight.w400, + letterSpacing: 0.4, + ), + ); + + EdgeInsets get padding => const EdgeInsets.all(16); + EdgeInsets get paddingSmall => const EdgeInsets.all(8); + Widget get horizontalSpacer => const SizedBox( + width: 16, + ); + Widget get horizontalSpacerSmall => const SizedBox( + width: 8, + ); + Widget get verticalSpacer => const SizedBox( + height: 16, + ); + Widget get verticalSpacerSmall => const SizedBox( + height: 8, + ); + Widget get verticalSpacerMax => const SizedBox( + height: 48, + ); + + ThemeData get darkThemeData => ThemeData( + useMaterial3: true, colorScheme: darkColorScheme, textTheme: textTheme); + + ThemeData get lightThemeData => ThemeData( + useMaterial3: true, colorScheme: lightColorScheme, textTheme: textTheme); + ThemeData get currentThemeData => + (AmbitoTheme.appThemeMode == ThemeMode.light) + ? lightThemeData + : darkThemeData; + + ThemeMode get mode => AmbitoTheme.appThemeMode; + + ColorScheme get currentColorScheme => + (AmbitoTheme.appThemeMode == ThemeMode.light) + ? lightColorScheme + : darkColorScheme; +} diff --git a/lib/src/pages/actions/action_detail_page.dart b/lib/src/pages/actions/action_detail_page.dart new file mode 100644 index 0000000..000cd47 --- /dev/null +++ b/lib/src/pages/actions/action_detail_page.dart @@ -0,0 +1,188 @@ +import 'package:ambito/src/entity/entities.dart'; +import 'package:ambito/src/entity/measure/measure_repository.dart'; +import 'package:ambito/src/pages/actions/cards/background_card.dart'; +import 'package:ambito/src/pages/actions/cards/biodiverisity_card.dart'; +import 'package:ambito/src/pages/actions/cards/creation_card.dart'; +import 'package:ambito/src/pages/actions/cards/description_card.dart'; +import 'package:ambito/src/pages/actions/cards/factsheet_card.dart'; +import 'package:ambito/src/pages/actions/cards/funding_card.dart'; +import 'package:ambito/src/pages/actions/cards/maintenance_card.dart'; +import 'package:ambito/src/pages/actions/cards/presets_card.dart'; +import 'package:ambito/src/pages/actions/cards/review_card.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_breadcrumb/flutter_breadcrumb.dart'; +import 'package:get/get.dart'; + +import '../../../main.dart'; +import '../../widgets/appbar/ambito_appbar.dart'; +import '../ambito_page.dart'; +import 'cards/advisor_card.dart'; +import 'cards/material_card.dart'; + +class ActionDetailPage extends AmbitoPage { + const ActionDetailPage({super.key}); + + @override + final String path = 'massnahme'; + @override + final String title = 'Maßname'; + + @override + State createState() => ActionDetailPageState(); +} + +class ActionDetailPageState extends State { + late String id; + + Widget content = const SizedBox(); + Measure? massnahme; + + @override + void initState() { + id = Get.parameters['id'] ?? ''; + if (id != '') { + massnahme = MeasureRepository().get(int.parse(id)) as Measure; + setState(() { + if (massnahme != null) { + content = _buildInfoPage(massnahme!); + } + }); + } + logger.d(id); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AmbitoAppbar( + links: const ['dashboard', 'massnahmen'], + ), + body: SingleChildScrollView( + child: content, + ), + ); + } + + Widget _buildInfoPage(Measure massnahme) { + return Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: BreadCrumb( + items: [ + BreadCrumbItem( + content: TextButton( + onPressed: () { + Get.offAndToNamed('/'); + }, + child: const Text('Start'), + ), + ), + BreadCrumbItem( + content: TextButton( + onPressed: () { + Get.offAndToNamed('/massnahmendatenbank'); + }, + child: const Text('Massnahmen'), + ), + ), + BreadCrumbItem( + content: Text( + massnahme.name ?? '', + ), + ), + ], + divider: const Icon(Icons.chevron_right), + ), + ), + Container( + width: double.infinity, + height: 400, + color: baseTheme.currentColorScheme.primary, + child: massnahme.getImage(), + ), + SizedBox( + width: 1140, + child: Expanded( + child: Column( + children: [ + baseTheme.verticalSpacer, + Align( + alignment: Alignment.centerLeft, + child: Text( + massnahme.name!, + style: baseTheme.currentThemeData.textTheme.titleLarge, + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + children: [ + DescriptionCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + BackgroundCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + PresetsCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + BiodiverisityCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + CreationCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + MaintenanceCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + FundingCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + ], + ), + ), + baseTheme.horizontalSpacer, + SizedBox( + width: 300, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + AdvisorCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + MaterialCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + FactsheetCard( + massnahme: massnahme, + ), + baseTheme.verticalSpacer, + ReviewCard( + massnahme: massnahme, + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/lib/src/pages/actions/actions_page.dart b/lib/src/pages/actions/actions_page.dart index df52918..8b5234d 100644 --- a/lib/src/pages/actions/actions_page.dart +++ b/lib/src/pages/actions/actions_page.dart @@ -1,51 +1,122 @@ +import 'package:ambito/src/entity/_general/filter/item_filter_repository.dart'; import 'package:ambito/src/entity/measure/measure_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/packages/ambito_notifier/notifier/filter_notifier.dart'; +import 'package:ambito/src/pages/ambito_page.dart'; +import 'package:ambito/src/widgets/appbar/ambito_appbar.dart'; +import 'package:ambito/src/widgets/form/fields/field_title.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_breadcrumb/flutter_breadcrumb.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:get/get.dart'; +import 'package:highlight_text/highlight_text.dart'; import '../../../main.dart'; import '../../entity/entities.dart'; +import '../../packages/ambito_theme/ambito_theme.dart'; -class ActionsPage extends StatefulWidget { +class ActionsPage extends AmbitoPage { const ActionsPage({super.key}); + @override + final String path = 'massnahmendatenbank'; + @override + final String title = 'Maßnamendatenbank'; + @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 effort = [], effect = [], region = []; + Set type = {}, areaType = {}, support = {}, months = {}; + String? filterType, + filterAreaType, + filterSupport, + filterMonths, + searchText = ''; + List? selectedMonths; List massnahmen = []; + Map words = {}; + String? preselect; + + final TextEditingController _searchController = TextEditingController(); + final FocusNode _searchFocusNode = FocusNode(); @override void initState() { + ambitoFilterNotifier.addListener(_changeListener); + + setState(() { + preselect = prefs.getString('selected_areaType'); + if (preselect != null && preselect!.isNotEmpty) { + filterAreaType = preselect; + ambitoFilterNotifier.setFilter('areaType', preselect!); + } + }); + _initializeData(); super.initState(); - massnahmen = MeasureRepository().getAll(); - effort = []; - effect = []; - type = {}; - areaType = {}; - region = []; - support = {}; } - buildCards() {} + void _changeListener() { + setState(() { + filterAreaType = ambitoFilterNotifier.getFilter('areaType'); + filterType = ambitoFilterNotifier.getFilter('group'); + }); + logger.d(ambitoFilterNotifier.activeIds); + } + + @override + void dispose() { + //ambitoFilterNotifier.dispose(); + super.dispose(); + } + + void _initializeData() { + massnahmen = MeasureRepository().getAll(); + _updateFilterSets(); + } + + void _updateFilterSets() { + final updatedTypes = {}, updatedAreaTypes = {}; + final updatedSupports = {}, updatedMonths = {}; + + for (final massnahme in massnahmen) { + if (massnahme.actionGroup?.value != null) { + updatedTypes.add(massnahme.actionGroup!.value!); + } + massnahme.factsheetAreaType?.forEach((aType) { + if (aType.value != null) updatedAreaTypes.add(aType.value!); + }); + massnahme.fundingPrograms?.forEach((aType) { + if (aType.value != null) updatedSupports.add(aType.value!); + }); + massnahme.timeFrame?.forEach((tfType) { + if (tfType.value != null) updatedMonths.add(tfType.value!); + }); + } + + setState(() { + type = updatedTypes; + areaType = updatedAreaTypes; + support = updatedSupports; + months = updatedMonths; + }); + } + + void _onSearchTextChanged(String value) { + setState(() { + searchText = value; + words = { + for (var word in value.split(' ')) + word: HighlightedWord( + textStyle: Theme.of(context).textTheme.headlineSmall?.copyWith( + color: Colors.white, backgroundColor: Colors.green.shade800)) + }; + }); + } @override Widget build(BuildContext context) { @@ -80,6 +151,21 @@ class ActionsPageState extends State { }); final actionCards = massnahmen.map((massnahme) { + List possibleMonths = List.generate( + 12, + (i) => FlutterI18n.translate( + context, + 'general.lists.months.${i + 1}', + ), + ); + + if (massnahme.timeFrame != null && massnahme.timeFrame.isNotEmpty) { + possibleMonths = []; + for (IdValueColor month in massnahme.timeFrame) { + possibleMonths.add(month.value!); + } + } + final typeMatches = filterType == null || massnahme.actionGroup?.value == filterType; final areaTypeMatches = filterAreaType == null || @@ -91,61 +177,82 @@ class ActionsPageState extends State { ?.any((aType) => aType.value == filterSupport) ?? false); + final searchMatches = searchText == '' || + ((massnahme.name.toLowerCase().contains(searchText?.toLowerCase())) ?? + false) || + ((massnahme.factsheetDefinition + .toLowerCase() + .contains(searchText?.toLowerCase())) ?? + false); + + final monthMatches = (selectedMonths == [] || selectedMonths == null) || + (_hasCommonItems(selectedMonths!, possibleMonths)); + setState(() { - visible[massnahme.id] = - typeMatches && areaTypeMatches && supportMatches; + visible[massnahme.id] = typeMatches && + areaTypeMatches && + supportMatches && + searchMatches && + monthMatches; }); return getCard(context, massnahme); }).toList(); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 32), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - getSpacer(), - Center( - child: SearchBar( - leading: const Icon(Icons.search), - onChanged: (value) { - for (Measure massnahme in massnahmen) { - if (!massnahme.name!.contains(value)) { - logger.d('$value not in ${massnahme.name}'); - setState(() { - visible[massnahme.id] = false; - }); - } else { - logger.d('$value in ${massnahme.name}'); - setState(() { - visible[massnahme.id] = true; - }); - } - } - }, - ), - ), - getSpacer(), - 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, + return Scaffold( + appBar: AmbitoAppbar( + links: const ['dashboard', 'massnahmen'], + ), + body: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: Alignment.centerLeft, + child: BreadCrumb( + items: [ + BreadCrumbItem( + content: TextButton( + onPressed: () { + Get.offAndToNamed('/'); + }, + child: const Text('Start'), ), ), - ), - ], + BreadCrumbItem( + content: const Text( + 'Maßnahmen', + ), + ), + ], + divider: const Icon(Icons.chevron_right), + ), ), - ), - getSpacer(), - ], + getSpacer(), + _buildSearchBar(), + getSpacer(), + getSpacer(), + Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(width: 300, child: _buildFilter(context)), + const SizedBox(width: 16), + Expanded( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: actionCards, + ), + ), + ), + ], + ), + ), + getSpacer(), + ], + ), ), ); } @@ -156,170 +263,99 @@ class ActionsPageState extends State { ); } - 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(), + Widget _buildSearchBar() { + return Center( + child: SearchBar( + controller: _searchController, + focusNode: _searchFocusNode, + elevation: WidgetStateProperty.all(0.0), + backgroundColor: WidgetStateProperty.all(Colors.white), + side: WidgetStateProperty.all(const BorderSide(color: Colors.black)), + leading: const Icon(Icons.search), + trailing: [ + if (_searchFocusNode.hasFocus && _searchController.text.isNotEmpty) + IconButton( + onPressed: () { + _searchController.clear(); + _searchFocusNode.unfocus(); + _onSearchTextChanged(''); + }, + icon: const Icon(Icons.clear, color: Colors.grey, size: 20), + ), + ], + onChanged: _onSearchTextChanged, ), ); + } - 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(), - ), + Widget _buildFilter(BuildContext context) { + return FormWidget( + type: FormWidgetType.vertical, + fields: [ + FieldTitle(text: 'Filter'), + ItemFilterRepository().getDropDown('areaType', 'Ort der Maßnahme'), + ItemFilterRepository().getDropDown('group', 'Art der Maßnahme'), + ItemFilterRepository().getDropDown('fundingProgram', 'Förderprogramm'), + ItemFilterRepository().getDropDown('month', 'Beginn der Maßnahme'), + ], ); - - 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, Measure massnahme) { - final Map actionGroupColors = { - 'Baulelemente': const Color(0xffFFD269).withOpacity(.4), - 'Begrünung': const Color(0xff40DD74).withOpacity(.4), - 'Bewirtschaftung': const Color(0xffBF72ED).withOpacity(.4), - 'Nisthilfe': const Color(0xffDAE3FD).withOpacity(.4), - 'Pflanzung': const Color(0xff40D6E9).withOpacity(.4), - 'Sondermaßnahmen': const Color(0xff689EF1).withOpacity(.4), - }; - - Color background = + final background = actionGroupColors[massnahme.actionGroup?.value] ?? Colors.white; - - CachedNetworkImage? image = massnahme.getThumbnail(); + final image = massnahme.getThumbnail(); return Visibility( visible: visible[massnahme.id] ?? false, - child: SizedBox( - width: 800, - child: Card( - elevation: 2, - color: Colors.white, - child: ClipPath( - clipper: ShapeBorderClipper( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), + child: InkWell( + onHover: (hovered) {}, + onTap: () async { + Get.toNamed('/massnahme/${massnahme.id}'); + }, + child: SizedBox( + width: 800, + child: Card( + elevation: 2, + color: Colors.white, child: Container( decoration: BoxDecoration( - border: Border( - left: BorderSide( - color: background, - width: 15, - ), - ), + border: Border(left: BorderSide(color: background, width: 15)), ), - 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, + padding: const EdgeInsets.all(32), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + image ?? const SizedBox(width: 300, height: 140), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextHighlight( + text: massnahme.name!, + words: words, + textStyle: Theme.of(context).textTheme.headlineSmall, + ), + const SizedBox(height: 8), + TextHighlight( + text: massnahme.factsheetDefinition ?? '', + words: words, + textStyle: Theme.of(context).textTheme.bodyMedium, + ), + ], ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - massnahme.name!, - style: Theme.of(context).textTheme.headlineSmall, - ), - const SizedBox( - height: 8, - ), - ExpandableText( - style: Theme.of(context).textTheme.bodyLarge, - massnahme.factsheetDefinition ?? '', - maxLines: 4, - expandText: 'mehr', - collapseText: 'weniger', - ) - ], - ), - ) - ], - ), + ), + ], ), ), ), - /*child: ,*/ ), ), ); } + + bool _hasCommonItems(List listOne, List listTwo) { + return listOne.toSet().intersection(listTwo.toSet()).isNotEmpty; + } } diff --git a/lib/src/pages/actions/actions_pre_page.dart b/lib/src/pages/actions/actions_pre_page.dart new file mode 100644 index 0000000..7130504 --- /dev/null +++ b/lib/src/pages/actions/actions_pre_page.dart @@ -0,0 +1,154 @@ +import 'package:ambito/src/entity/_general/filter/item_filter_repository.dart'; +import 'package:ambito/src/entity/entities.dart'; +import 'package:ambito/src/entity/measure/measure_repository.dart'; +import 'package:ambito/src/pages/ambito_page.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../../main.dart'; +import '../../packages/ambito_theme/ambito_theme.dart'; +import '../../widgets/appbar/ambito_appbar.dart'; + +class ActionsPrePage extends AmbitoPage { + const ActionsPrePage({super.key}); + + @override + final String path = 'massnahmen'; + @override + final String title = 'Maßnamen'; + + @override + State createState() => ActionsPrePageState(); +} + +class ActionsPrePageState extends State { + List cards = []; + Map counter = {}; + Map ids = {}; + int counterComplete = 0; + + @override + void initState() { + List? filters = ItemFilterRepository().getByType('areaType'); + + counterComplete = MeasureRepository().getMeasureCount(); + + for (ItemFilter filter in filters!) { + setState(() { + cards.add( + InkWell( + onTap: () { + prefs.setString('selected_areaType', filter.name!).then((value) { + Get.toNamed('/massnahmendatenbank'); + setState(() {}); + }); + }, + onHover: (value) {}, + child: SizedBox( + width: 300, + height: 400, + child: Card( + color: actionAreaColors[filter.name!], + child: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8.0), + child: Image.asset( + filter.image!, + ), + ), + baseTheme.verticalSpacer, + Padding( + padding: const EdgeInsets.only(left: 16, right: 16), + child: Text( + filter.name!, + style: baseTheme.currentThemeData.textTheme.titleLarge + ?.copyWith( + color: actionAreaFGColors[filter.name!], + fontWeight: FontWeight.bold, + ), + ), + ), + baseTheme.verticalSpacer, + Padding( + padding: const EdgeInsets.only(left: 16, right: 16), + child: Text( + filter.description!, + style: baseTheme.currentThemeData.textTheme.bodyMedium + ?.copyWith( + color: baseTheme.currentColorScheme.onSurface, + ), + ), + ), + const Spacer(), + Padding( + padding: const EdgeInsets.only( + left: 16, right: 16, bottom: 16), + child: Text( + 'Anzahl: ${filter.ids!.length}', + style: baseTheme.currentThemeData.textTheme.titleMedium + ?.copyWith( + color: actionAreaFGColors[filter.name!], + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + ), + ), + ); + }); + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AmbitoAppbar( + links: const ['dashboard', 'massnahmen'], + ), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + baseTheme.verticalSpacerMax, + Text( + 'Maßnahmenkategorien', + textAlign: TextAlign.start, + style: + baseTheme.currentThemeData.textTheme.headlineLarge?.copyWith( + color: baseTheme.currentColorScheme.onSurface, + ), + ), + baseTheme.verticalSpacerMax, + Wrap( + alignment: WrapAlignment.center, + spacing: 16, + children: cards, + ), + baseTheme.verticalSpacerMax, + TextButton( + onPressed: () async { + await prefs.setString('selected_areaType', ''); + await Get.toNamed('/massnahmendatenbank'); + }, + child: Text( + 'Zeig mir alle $counterComplete Maßnahmen...', + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.blueAccent, + ), + )) + ], + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/advisor_card.dart b/lib/src/pages/actions/cards/advisor_card.dart new file mode 100644 index 0000000..c68b5ba --- /dev/null +++ b/lib/src/pages/actions/cards/advisor_card.dart @@ -0,0 +1,42 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class AdvisorCard extends StatelessWidget { + const AdvisorCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.tertiary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.advisor.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + Text( + 'Max Mustermann', + style: baseTheme.currentThemeData.textTheme.bodyMedium, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/background_card.dart b/lib/src/pages/actions/cards/background_card.dart new file mode 100644 index 0000000..fcd0bb2 --- /dev/null +++ b/lib/src/pages/actions/cards/background_card.dart @@ -0,0 +1,57 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class BackgroundCard extends StatelessWidget { + const BackgroundCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.secondary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.background.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + Text( + context.translate('page.actionDetailPage.background.areaType'), + style: baseTheme.currentThemeData.textTheme.titleSmall, + ), + baseTheme.verticalSpacerSmall, + Text( + massnahme.factsheetLocation.toString(), + style: baseTheme.currentThemeData.textTheme.bodyMedium, + ), + baseTheme.verticalSpacer, + Text( + context.translate('page.actionDetailPage.background.target'), + style: baseTheme.currentThemeData.textTheme.titleSmall, + ), + baseTheme.verticalSpacerSmall, + Text( + massnahme.factsheetTarget.toString(), + style: baseTheme.currentThemeData.textTheme.bodyMedium, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/biodiverisity_card.dart b/lib/src/pages/actions/cards/biodiverisity_card.dart new file mode 100644 index 0000000..3330cd5 --- /dev/null +++ b/lib/src/pages/actions/cards/biodiverisity_card.dart @@ -0,0 +1,42 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class BiodiverisityCard extends StatelessWidget { + const BiodiverisityCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.secondary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.biodiversity.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + Text( + massnahme.oekologischeRelevanzBackground.toString(), + style: baseTheme.currentThemeData.textTheme.bodyMedium, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/creation_card.dart b/lib/src/pages/actions/cards/creation_card.dart new file mode 100644 index 0000000..ff4487e --- /dev/null +++ b/lib/src/pages/actions/cards/creation_card.dart @@ -0,0 +1,51 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class CreationCard extends StatelessWidget { + const CreationCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.secondary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.creation.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + Text( + context.translate('page.actionDetailPage.creation.timeFrame'), + style: baseTheme.currentThemeData.textTheme.titleSmall, + ), + baseTheme.verticalSpacer, + Text( + massnahme.timeFrame + ?.map((item) => item.value) + .toList() + .join(', ') ?? + '', + style: baseTheme.currentThemeData.textTheme.bodyMedium, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/description_card.dart b/lib/src/pages/actions/cards/description_card.dart new file mode 100644 index 0000000..6425a31 --- /dev/null +++ b/lib/src/pages/actions/cards/description_card.dart @@ -0,0 +1,42 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class DescriptionCard extends StatelessWidget { + const DescriptionCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.secondary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.description.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + Text( + massnahme.factsheetDefinition ?? '', + style: baseTheme.currentThemeData.textTheme.bodyMedium, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/factsheet_card.dart b/lib/src/pages/actions/cards/factsheet_card.dart new file mode 100644 index 0000000..ac71818 --- /dev/null +++ b/lib/src/pages/actions/cards/factsheet_card.dart @@ -0,0 +1,63 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class FactsheetCard extends StatelessWidget { + const FactsheetCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.tertiary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.factsheet.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + ], + ), + ), + ), + ); + } + + _getSortedMaterials(BuildContext context) { + List items = []; + if (massnahme.materialAction != null) { + for (IdValueColor ivc in massnahme.materialAction!) { + items.add(ivc.value!); + } + } + items.sort((a, b) => a.toString().compareTo(b.toString())); + List tiles = []; + for (String item in items) { + tiles.add( + ListTile( + leading: Icon(Icons.fiber_manual_record), + title: Text( + item, + style: Theme.of(context).textTheme.bodyMedium, + ), + ), + ); + } + return Column( + children: tiles, + ); + } +} diff --git a/lib/src/pages/actions/cards/funding_card.dart b/lib/src/pages/actions/cards/funding_card.dart new file mode 100644 index 0000000..4919c17 --- /dev/null +++ b/lib/src/pages/actions/cards/funding_card.dart @@ -0,0 +1,38 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class FundingCard extends StatelessWidget { + const FundingCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.secondary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.funding.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/maintenance_card.dart b/lib/src/pages/actions/cards/maintenance_card.dart new file mode 100644 index 0000000..667b8d4 --- /dev/null +++ b/lib/src/pages/actions/cards/maintenance_card.dart @@ -0,0 +1,38 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class MaintenanceCard extends StatelessWidget { + const MaintenanceCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.secondary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.maintenance.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/material_card.dart b/lib/src/pages/actions/cards/material_card.dart new file mode 100644 index 0000000..f2cb771 --- /dev/null +++ b/lib/src/pages/actions/cards/material_card.dart @@ -0,0 +1,71 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class MaterialCard extends StatelessWidget { + const MaterialCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.tertiary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.material.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + _getSortedMaterials(context), + baseTheme.verticalSpacer, + if (massnahme.costsMaterial != null) + Text(context.translate( + 'page.actionDetailPage.material.suggested_price') + + massnahme.costsMaterial + + ' €'), + baseTheme.verticalSpacer, + ], + ), + ), + ), + ); + } + + _getSortedMaterials(BuildContext context) { + List items = []; + if (massnahme.materialAction != null) { + for (IdValueColor ivc in massnahme.materialAction!) { + items.add(ivc.value!); + } + } + items.sort((a, b) => a.toString().compareTo(b.toString())); + List tiles = []; + for (String item in items) { + tiles.add( + ListTile( + leading: Icon(Icons.fiber_manual_record), + title: Text( + item, + style: Theme.of(context).textTheme.bodyMedium, + ), + ), + ); + } + return Column( + children: tiles, + ); + } +} diff --git a/lib/src/pages/actions/cards/presets_card.dart b/lib/src/pages/actions/cards/presets_card.dart new file mode 100644 index 0000000..8a40994 --- /dev/null +++ b/lib/src/pages/actions/cards/presets_card.dart @@ -0,0 +1,52 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class PresetsCard extends StatelessWidget { + const PresetsCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.secondary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.presets.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + Text( + massnahme.remarkablePresets.toString(), + style: baseTheme.currentThemeData.textTheme.bodyMedium, + ), + baseTheme.verticalSpacer, + Text( + context.translate('page.actionDetailPage.presets.tips'), + style: baseTheme.currentThemeData.textTheme.titleSmall, + ), + baseTheme.verticalSpacerSmall, + Text( + massnahme.tipsPresets.toString(), + style: baseTheme.currentThemeData.textTheme.bodyMedium, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/actions/cards/review_card.dart b/lib/src/pages/actions/cards/review_card.dart new file mode 100644 index 0000000..b1456e1 --- /dev/null +++ b/lib/src/pages/actions/cards/review_card.dart @@ -0,0 +1,66 @@ +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_rating_stars/flutter_rating_stars.dart'; + +import '../../../../main.dart'; +import '../../../entity/entities.dart'; + +class ReviewCard extends StatelessWidget { + const ReviewCard({super.key, required this.massnahme}); + + final Measure massnahme; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + elevation: 0, + color: baseTheme.currentColorScheme.tertiary, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translate('page.actionDetailPage.review.title'), + style: baseTheme.currentThemeData.textTheme.titleMedium, + ), + baseTheme.verticalSpacer, + RatingStars( + value: 4.5, + onValueChanged: (v) {}, + starBuilder: (index, color) => Icon( + Icons.star, + color: color, + ), + starCount: 5, + starSize: 32, + valueLabelColor: const Color(0xff9b9b9b), + valueLabelTextStyle: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + fontSize: 12.0), + valueLabelRadius: 10, + maxValue: 5, + starSpacing: 2, + maxValueVisibility: true, + valueLabelVisibility: false, + animationDuration: const Duration(milliseconds: 1000), + valueLabelPadding: + const EdgeInsets.symmetric(vertical: 1, horizontal: 8), + valueLabelMargin: const EdgeInsets.only(right: 8), + starOffColor: const Color(0xffe7e8ea), + starColor: Colors.grey.shade600, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/ambito_page.dart b/lib/src/pages/ambito_page.dart new file mode 100644 index 0000000..07ed55b --- /dev/null +++ b/lib/src/pages/ambito_page.dart @@ -0,0 +1,8 @@ +import 'package:flutter/cupertino.dart'; + +abstract class AmbitoPage extends StatefulWidget { + abstract final String path; + abstract final String title; + + const AmbitoPage({super.key}); +} diff --git a/lib/src/pages/calendar/calendar_page.dart b/lib/src/pages/calendar/calendar_page.dart new file mode 100644 index 0000000..77a5b88 --- /dev/null +++ b/lib/src/pages/calendar/calendar_page.dart @@ -0,0 +1,175 @@ +import 'package:ambito/src/entity/_general/filter/item_filter.dart'; +import 'package:ambito/src/entity/_general/filter/item_filter_repository.dart'; +import 'package:ambito/src/entity/measure/measure.dart'; +import 'package:ambito/src/entity/measure/measure_repository.dart'; +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:ambito/src/packages/ambito_theme/ambito_theme.dart'; +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_calendar/calendar.dart'; + +import '../../widgets/appbar/ambito_appbar.dart'; + +class CalendarPage extends StatefulWidget { + const CalendarPage({super.key}); + + @override + State createState() => CalendarPageState(); +} + +class CalendarPageState extends State { + List appointments = []; + + List months = [ + 'Januar', + 'Februar', + 'März', + 'April', + 'Mai', + 'Juni', + 'Juli', + 'August', + 'September', + 'Oktober', + 'November', + 'Dezember', + ]; + List? monthFilter = []; + + @override + void initState() { + initDataSource(); + super.initState(); + } + + initDataSource() { + monthFilter = ItemFilterRepository().getByType('month'); + for (String month in months) { + DateTime now = DateTime.now(); + int monthInt = months.indexOf(month) + 1; + + DateTime startDate = DateTime(now.year, monthInt, 1, 0, 0, 0); + DateTime endDate = DateTime( + now.year, monthInt, startDate.lastDayOfMonth.day, 23, 59, 59); + + ItemFilter? itemFilter = + monthFilter?.firstWhereOrNull((item) => item.name == month); + if (itemFilter != null) { + List currentMeasures = + MeasureRepository().getByIds(itemFilter.ids!); + for (var measure in currentMeasures) { + appointments.add( + Appointment( + startTime: startDate, + endTime: endDate, + isAllDay: true, + subject: measure!.name ?? '', + color: actionGroupColors[measure.actionGroup!.value!]!, + ), + ); + } + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AmbitoAppbar( + links: const ['dashboard', 'massnahmen'], + ), + body: Center( + child: Padding( + padding: const EdgeInsets.all(32), + child: SfCalendar( + firstDayOfWeek: 1, + showNavigationArrow: true, + view: CalendarView.month, + dataSource: _AppointmentDataSource(appointments), + monthViewSettings: const MonthViewSettings( + appointmentDisplayMode: MonthAppointmentDisplayMode.appointment, + appointmentDisplayCount: 64, + ), + ), + ), + ), + ); + } + + _AppointmentDataSource _getCalendarDataSource() { + List appointments = []; + appointments.add(Appointment( + startTime: DateTime.now(), + endTime: DateTime.now().add(Duration(minutes: 10)), + subject: 'Meeting', + isAllDay: true, + color: Colors.blue, + startTimeZone: '', + endTimeZone: '', + )); + + return _AppointmentDataSource(appointments); + } +} + +class _AppointmentDataSource extends CalendarDataSource { + _AppointmentDataSource(List source) { + appointments = source; + } +} + +/*class ActionDataSource extends CalendarDataSource { + ActionDataSource(List source) { + appointments = source; + } + + @override + DateTime getStartTime(int index) { + return appointments![index].from; + } + + @override + DateTime getEndTime(int index) { + return appointments![index].to; + } + + @override + bool isAllDay(int index) { + return appointments![index].isAllDay; + } + + @override + String getSubject(int index) { + return appointments![index].eventName; + } + + @override + String getStartTimeZone(int index) { + return appointments![index].startTimeZone; + } + + @override + String getEndTimeZone(int index) { + return appointments![index].endTimeZone; + } + + @override + Color getColor(int index) { + return appointments![index].background; + } +} + +class Action { + Action( + {this.eventName = '', + required this.from, + required this.to, + required this.background, + this.isAllDay = false}); + + String eventName; + DateTime from; + DateTime to; + Color background; + bool isAllDay; +}*/ diff --git a/lib/src/pages/calendar/calendar_page_year.dart b/lib/src/pages/calendar/calendar_page_year.dart new file mode 100644 index 0000000..086b4d3 --- /dev/null +++ b/lib/src/pages/calendar/calendar_page_year.dart @@ -0,0 +1,171 @@ +import 'package:ambito/main.dart'; +import 'package:ambito/src/entity/_general/filter/item_filter.dart'; +import 'package:ambito/src/entity/measure/measure_repository.dart'; +import 'package:flutter/material.dart'; + +import '../../widgets/appbar/ambito_appbar.dart'; + +class CalendarPageYear extends StatefulWidget { + const CalendarPageYear({super.key}); + + @override + State createState() => CalendarPageYearState(); +} + +class CalendarPageYearState extends State { + List rows = []; + + List months = [ + 'Januar', + 'Februar', + 'März', + 'April', + 'Mai', + 'Juni', + 'Juli', + 'August', + 'September', + 'Oktober', + 'November', + 'Dezember', + ]; + List? monthFilter = []; + + @override + void initState() { + initDataSource(); + super.initState(); + } + + initDataSource() { + List cells = [ + TableCell( + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + 'Maßnahme', + style: baseTheme.currentThemeData.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ]; + for (String month in months) { + cells.add( + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Text( + textAlign: TextAlign.center, + month, + style: baseTheme.currentThemeData.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } + rows.add(TableRow(children: cells)); + var massnahmen = MeasureRepository().getAllOrdered(); + for (var massnahme in massnahmen) { + if (massnahme.name != null && massnahme.name!.isNotEmpty) { + cells = [ + TableCell( + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + massnahme.name!, + ), + ), + ), + ]; + for (String month in months) { + if (massnahme.timeFrame! + .where((ele) => ele.value == month) + .isNotEmpty) { + cells.add( + TableCell( + child: Container( + width: double.infinity, + height: 44, + color: baseTheme.currentColorScheme.primary, + ), + ), + ); + } else { + cells.add( + TableCell( + child: Container( + width: double.infinity, + height: 44, + color: Colors.transparent, + ), + ), + ); + } + } + rows.add( + TableRow( + children: cells, + ), + ); + } + } + } + + @override + Widget build(BuildContext context) { + double fixedWidth = 120; + return Scaffold( + appBar: AmbitoAppbar( + links: const ['dashboard', 'massnahmen'], + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(32), + child: Table( + border: TableBorder( + top: const BorderSide( + width: 2, + color: Colors.black, + ), + left: const BorderSide( + width: 2, + color: Colors.black, + ), + right: const BorderSide( + width: 2, + color: Colors.black, + ), + bottom: const BorderSide( + width: 2, + color: Colors.black, + ), + horizontalInside: BorderSide( + width: 1, + color: Colors.black.withOpacity(.6), + ), + ), + columnWidths: { + 0: FlexColumnWidth(300), + 1: FlexColumnWidth(fixedWidth), + 2: FlexColumnWidth(fixedWidth), + 3: FlexColumnWidth(fixedWidth), + 4: FlexColumnWidth(fixedWidth), + 5: FlexColumnWidth(fixedWidth), + 6: FlexColumnWidth(fixedWidth), + 7: FlexColumnWidth(fixedWidth), + 8: FlexColumnWidth(fixedWidth), + 9: FlexColumnWidth(fixedWidth), + 10: FlexColumnWidth(fixedWidth), + 11: FlexColumnWidth(fixedWidth), + 12: FlexColumnWidth(fixedWidth), + 13: FlexColumnWidth(fixedWidth), + }, + children: rows, + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/loading/loading_page.dart b/lib/src/pages/loading/loading_page.dart deleted file mode 100644 index 862f927..0000000 --- a/lib/src/pages/loading/loading_page.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:ambito/src/pages/start/start_page.dart'; -import 'package:flutter/material.dart'; - -class LoadingPage extends StatelessWidget { - const LoadingPage({super.key}); - - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: Future.delayed( - const Duration(seconds: 1), - () { - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute( - builder: (context) { - return const StartPage(); - }, - ), - (route) => false, - ); - }, - ), - builder: (context, snapshot) { - if (snapshot.connectionState != ConnectionState.done) { - return Center( - child: Hero( - tag: 'logo', - child: Image.asset('assets/images/logo_trans.png')), - ); - } - return Center( - child: Hero( - tag: 'logo', child: Image.asset('assets/images/logo_trans.png')), - ); - }, - ); - } -} diff --git a/lib/src/pages/start/start_page.dart b/lib/src/pages/start/start_page.dart index 83e578f..b943dd2 100644 --- a/lib/src/pages/start/start_page.dart +++ b/lib/src/pages/start/start_page.dart @@ -1,24 +1,34 @@ -import 'package:ambito/src/extensions/extensions.dart'; -import 'package:flutter/material.dart'; +import 'dart:html' as html; -import '../actions/actions_page.dart'; +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:ambito/src/pages/ambito_page.dart'; +import 'package:ambito/src/widgets/appbar/ambito_appbar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_breadcrumb/flutter_breadcrumb.dart'; +import 'package:get/get.dart'; + +import '../../../main.dart'; class StartPage extends StatefulWidget { - const StartPage({super.key}); + const StartPage({super.key, required this.activeLink}); + + final AmbitoPage activeLink; @override State createState() => StartPageState(); } class StartPageState extends State { - String activeLink = ''; Widget content = const SizedBox(); + String title = ''; @override void initState() { setState(() { - activeLink = 'database'; - content = const ActionsPage(); + content = widget.activeLink; + logger.d(widget.activeLink.title); + html.window.history.pushState( + null, widget.activeLink.title, '#/${widget.activeLink.path}'); }); super.initState(); } @@ -26,48 +36,41 @@ class StartPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - leading: Padding( - padding: const EdgeInsets.all(8), - child: Hero( - tag: 'logo', - child: Image.asset( - 'assets/images/logo_trans.png', - ), - ), - ), - leadingWidth: 80, - centerTitle: true, - title: _linkButton('database'), - toolbarHeight: 80, - backgroundColor: Colors.grey.withOpacity(.4), - actions: [ - IconButton(onPressed: () {}, icon: const Icon(Icons.person)), - const SizedBox( - width: 30, - ) - ], - ), - body: const Column( + appBar: AmbitoAppbar(), + body: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - SizedBox(height: 50), + if (widget.activeLink.path != 'massnahmen') + Align( + alignment: Alignment.centerLeft, + child: BreadCrumb( + items: [ + BreadCrumbItem( + content: TextButton( + onPressed: () { + Get.offAndToNamed('/'); + }, + child: const Text('Start'), + ), + ), + BreadCrumbItem( + content: Text( + widget.activeLink.title, + ), + ), + ], + divider: const Icon(Icons.chevron_right), + ), + ), + const SizedBox(height: 50), Expanded( - child: ActionsPage(), + child: content, ), ], )); } - Widget getContent() { - if (activeLink == 'database') { - return const ActionsPage(); - } - return Text(activeLink); - } - - Widget _linkButton(String link) { + Widget _linkButton(String link, Widget targetPage) { double fontSize = 20; return TextButton( style: ButtonStyle( @@ -77,16 +80,14 @@ class StartPageState extends State { }), ), onPressed: () { - setState(() { - activeLink = link; - }); + Get.offAndToNamed('/'); }, child: Text( context.translate('page.start.links.$link.title'), style: TextStyle( fontSize: fontSize, fontWeight: FontWeight.bold, - color: (activeLink == link) ? Colors.grey.shade800 : Colors.black, + //color: (activeLink == link) ? Colors.grey.shade800 : Colors.black, ), ), ); diff --git a/lib/src/widgets/appbar/ambito_appbar.dart b/lib/src/widgets/appbar/ambito_appbar.dart new file mode 100644 index 0000000..04a77f3 --- /dev/null +++ b/lib/src/widgets/appbar/ambito_appbar.dart @@ -0,0 +1,98 @@ +import 'package:ambito/main.dart'; +import 'package:ambito/src/extensions/extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class AmbitoAppbar extends AppBar { + AmbitoAppbar({super.key, List? links}) + : super( + automaticallyImplyLeading: false, + leading: Padding( + padding: const EdgeInsets.all(8), + child: Hero( + tag: 'logo', + child: GestureDetector( + onTap: () { + Get.toNamed('/'); + }, + child: Image.asset( + 'assets/images/logo_trans.png', + ), + ), + ), + ), + leadingWidth: 80, + centerTitle: true, + title: Builder( + builder: (context) => _links(context, links), + ), + toolbarHeight: 80, + backgroundColor: baseTheme.currentColorScheme.primaryContainer, + actions: [ + IconButton( + onPressed: () { + Get.toNamed('/kalender/jahr'); + }, + icon: Icon( + Icons.calendar_view_month, + color: baseTheme.currentColorScheme.primary, + ), + ), + IconButton( + onPressed: () { + Get.toNamed('/kalender'); + }, + icon: Icon( + Icons.calendar_month, + color: baseTheme.currentColorScheme.primary, + ), + ), + IconButton( + onPressed: () {}, + icon: Icon( + Icons.person, + color: baseTheme.currentColorScheme.primary, + ), + ), + const SizedBox( + width: 30, + ) + ], + ); + + static Widget _links(BuildContext context, List? links) { + List linkButtons = []; + if (links != null && links.isNotEmpty) { + for (String link in links) { + linkButtons.add(_linkButton(context, link)); + } + } + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: linkButtons, + ); + } + + static Widget _linkButton(BuildContext context, String link) { + double fontSize = 20; + return TextButton( + style: ButtonStyle( + overlayColor: + WidgetStateProperty.resolveWith((Set states) { + return Colors.transparent; + }), + ), + onPressed: () { + Get.offAndToNamed('/$link'); + }, + child: Text( + context.translate('page.start.links.$link.title'), + style: TextStyle( + fontSize: fontSize, + fontWeight: FontWeight.bold, + //color: (activeLink == link) ? Colors.grey.shade800 : Colors.black, + ), + ), + ); + } +} diff --git a/lib/src/widgets/form/fields/field_daterangepicker.dart b/lib/src/widgets/form/fields/field_daterangepicker.dart index 61f5c7f..aea3e00 100644 --- a/lib/src/widgets/form/fields/field_daterangepicker.dart +++ b/lib/src/widgets/form/fields/field_daterangepicker.dart @@ -27,29 +27,5 @@ class FieldDaterangepicker extends FormWidgetField { name: name, firstDate: now.firstDayOfYear(), lastDate: now.lastDayOfYear()); - - return FormBuilderDropdown( - name: name, - initialValue: filterValue, - decoration: InputDecoration( - labelText: label, - prefix: IconButton( - icon: const Icon(Icons.cancel_outlined), - onPressed: onClear, - ), - hintText: label, - ), - onReset: onClear, - onChanged: onSelected, - items: entries - .map( - (entry) => DropdownMenuItem( - value: entry, - alignment: Alignment.centerLeft, - child: Text(entry), - ), - ) - .toList(), - ); } } diff --git a/lib/src/widgets/form/fields/field_dropdown.dart b/lib/src/widgets/form/fields/field_dropdown.dart index 8ec763c..e69671e 100644 --- a/lib/src/widgets/form/fields/field_dropdown.dart +++ b/lib/src/widgets/form/fields/field_dropdown.dart @@ -3,13 +3,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; class FieldDropdown extends FormWidgetField { - FieldDropdown( - {required this.name, - required this.label, - required this.filterValue, - required this.onClear, - required this.onSelected, - required this.entries}); + FieldDropdown({ + required this.name, + required this.label, + required this.filterValue, + required this.onClear, + required this.onSelected, + required this.entries, + }); final String name; final String label; @@ -26,7 +27,9 @@ class FieldDropdown extends FormWidgetField { decoration: InputDecoration( labelText: label, prefix: IconButton( - icon: const Icon(Icons.cancel_outlined), + icon: const Icon( + Icons.cancel_outlined, + ), onPressed: onClear, ), hintText: label, @@ -38,7 +41,9 @@ class FieldDropdown extends FormWidgetField { (entry) => DropdownMenuItem( value: entry, alignment: Alignment.centerLeft, - child: Text(entry), + child: Text( + entry, + ), ), ) .toList(), diff --git a/lib/src/widgets/form/fields/field_monthsrangepicker.dart b/lib/src/widgets/form/fields/field_monthsrangepicker.dart index 20b3c40..bc305ef 100644 --- a/lib/src/widgets/form/fields/field_monthsrangepicker.dart +++ b/lib/src/widgets/form/fields/field_monthsrangepicker.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:syncfusion_flutter_datepicker/datepicker.dart'; import '../form_widget.dart'; @@ -16,7 +17,7 @@ class FieldMonthsRangepicker extends FormWidgetField { final String label; final String? filterValue; final VoidCallback onClear; - final void Function(String?) onSelected; + final void Function(DateRangePickerSelectionChangedArgs? args) onSelected; final List entries; @override @@ -25,9 +26,29 @@ class FieldMonthsRangepicker extends FormWidgetField { minDate: DateTime(2024, 1), maxDate: DateTime(2024, 12, 31), allowViewNavigation: false, + showNavigationArrow: false, + headerHeight: 0, view: DateRangePickerView.year, selectionMode: DateRangePickerSelectionMode.range, - onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {}, + onSelectionChanged: onSelected, ); } + + static List getMonths(DateTime createdDate, int length) { + DateFormat dateFormat = DateFormat.MMMM('de_DE'); + + List years = []; + + int currentYear = createdDate.year; + int currentMonth = createdDate.month; + for (int i = 0; i < length; i++) { + createdDate = DateTime(currentYear, currentMonth + i); + years.add(dateFormat.format(createdDate)); + + if (currentMonth + i == 1) { + currentYear += 1; + } + } + return years; + } } diff --git a/lib/src/widgets/form/fields/field_searchbar.dart b/lib/src/widgets/form/fields/field_searchbar.dart new file mode 100644 index 0000000..fd3255e --- /dev/null +++ b/lib/src/widgets/form/fields/field_searchbar.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class FieldSearchBar extends StatelessWidget { + final TextEditingController _searchController = TextEditingController(); + final FocusNode _searchFocusNode = FocusNode(); + final Function() deleteAction; + final Function(String value) onChange; + final String searchString; + + FieldSearchBar( + {super.key, + required this.deleteAction, + required this.onChange, + required this.searchString}); + + @override + Widget build(BuildContext context) { + return SearchBar( + controller: _searchController, + focusNode: _searchFocusNode, + elevation: WidgetStateProperty.all(0.0), + backgroundColor: WidgetStateProperty.all(Colors.white), + side: WidgetStateProperty.all( + const BorderSide( + color: Colors.black, + ), + ), + leading: const Icon(Icons.search), + trailing: [ + if (_searchFocusNode.hasFocus && _searchController.text.isNotEmpty) + IconButton( + onPressed: () { + _searchController.clear(); + _searchFocusNode.unfocus(); + deleteAction; + }, + icon: const Icon( + Icons.clear, + color: Colors.grey, + size: 20, + ), + ), + ], + onChanged: onChange, + ); + } +} diff --git a/lib/src/widgets/form/fields/field_title.dart b/lib/src/widgets/form/fields/field_title.dart new file mode 100644 index 0000000..c968bf3 --- /dev/null +++ b/lib/src/widgets/form/fields/field_title.dart @@ -0,0 +1,23 @@ +import 'package:ambito/main.dart'; +import 'package:ambito/src/widgets/form/form_widget.dart'; +import 'package:flutter/material.dart'; + +class FieldTitle extends FormWidgetField { + FieldTitle({ + required this.text, + }); + + final String text; + + @override + Widget get() { + return Align( + alignment: Alignment.centerLeft, + child: Text( + text, + textAlign: TextAlign.start, + style: baseTheme.currentThemeData.textTheme.titleLarge, + ), + ); + } +} diff --git a/lib/src/widgets/form/form_widget.dart b/lib/src/widgets/form/form_widget.dart index bc94192..eef7e5a 100644 --- a/lib/src/widgets/form/form_widget.dart +++ b/lib/src/widgets/form/form_widget.dart @@ -23,11 +23,20 @@ class FormWidget extends StatelessWidget { key: _formKey, child: (type == FormWidgetType.vertical) ? Column( - children: fields.map((element) => element.get()).toList(), + children: fields + .map((element) => _getElementVertical(element)) + .toList(), ) : Row( children: fields.map((element) => element.get()).toList(), ), )); } + + Widget _getElementVertical(FormWidgetField element) { + return Padding( + padding: const EdgeInsets.only(bottom: 16), + child: element.get(), + ); + } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index efa0599..6885312 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,11 +8,13 @@ import Foundation import geolocator_apple import isar_flutter_libs import path_provider_foundation +import shared_preferences_foundation import sqflite_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 4a4999e..50accb4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -170,12 +170,12 @@ packages: dependency: transitive description: name: code_builder - sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" url: "https://pub.dev" source: hosted - version: "4.10.0" + version: "4.10.1" collection: - dependency: transitive + dependency: "direct main" description: name: collection sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a @@ -307,6 +307,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_breadcrumb: + dependency: "direct main" + description: + name: flutter_breadcrumb + sha256: "1531680034def621878562ad763079933dabe9f9f5d5add5a094190edc33259b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" flutter_cache_manager: dependency: transitive description: @@ -384,6 +392,14 @@ packages: url: "https://pub.dev" source: hosted version: "9.1.1" + flutter_rating_stars: + dependency: "direct main" + description: + name: flutter_rating_stars + sha256: "09dfa831aac2e5128fe70c5a8bd63ff4463180d5ff8545f7379c5b209d22ce1d" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter_test: dependency: "direct dev" description: flutter @@ -466,6 +482,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" graphs: dependency: transitive description: @@ -474,6 +498,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + highlight_text: + dependency: "direct main" + description: + name: highlight_text + sha256: c5c6ae54f89183b10b1029ab33549d32e5f52841524fd0da3df92e11c4534127 + url: "https://pub.dev" + source: hosted + version: "1.8.0" http: dependency: "direct main" description: @@ -718,10 +750,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: @@ -762,6 +794,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + pedantic: + dependency: transitive + description: + name: pedantic + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" + source: hosted + version: "1.11.1" permission_handler: dependency: "direct main" description: @@ -890,6 +930,62 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" shelf: dependency: transitive description: @@ -1015,30 +1111,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + syncfusion_flutter_calendar: + dependency: "direct main" + description: + name: syncfusion_flutter_calendar + sha256: "769d3bbf8743922d74b242a968366661bd7b2973b3d34af9b9bc865874a520d9" + url: "https://pub.dev" + source: hosted + version: "27.1.58" syncfusion_flutter_core: dependency: transitive description: name: syncfusion_flutter_core - sha256: dde81d3a318d914e26b6882051c486b0f5e4fa13e7bc3661741de78f0397fe64 + sha256: "31d2ddf410ee41abb3ecf85b7b6e8e1563307ad52ee784ddd91337e30280f715" url: "https://pub.dev" source: hosted - version: "27.1.56" + version: "27.1.58" syncfusion_flutter_datepicker: dependency: "direct main" description: name: syncfusion_flutter_datepicker - sha256: e4d42b03b69e80b5936f44d420f9577542f8b156ba5ee78a05e28b23ed63c850 + sha256: e25797401bec43cd64c475150f87150e8bc3e67212d4d1273ff35483ea793a8b url: "https://pub.dev" source: hosted - version: "27.1.56" + version: "27.1.58" syncfusion_localizations: dependency: "direct main" description: name: syncfusion_localizations - sha256: "6dbc2eab1d70fad7b8501c44198bef4d36748cc6860252dfd4c8cfe2f3b10e7b" + sha256: a74b674f8d691927bebc10d19966539ecc92fa3b472c85df57e565f43e18483d url: "https://pub.dev" source: hosted - version: "27.1.56" + version: "27.1.58" synchronized: dependency: transitive description: @@ -1063,6 +1167,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2" + timezone: + dependency: "direct main" + description: + name: timezone + sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" + url: "https://pub.dev" + source: hosted + version: "0.9.4" timing: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fef18cd..81a396c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,6 +43,14 @@ dependencies: syncfusion_flutter_datepicker: ^27.1.50 syncfusion_localizations: ^27.1.52 flutter_dotenv: ^5.2.1 + highlight_text: ^1.8.0 + shared_preferences: ^2.3.2 + flutter_breadcrumb: ^1.0.1 + google_fonts: ^6.2.1 + collection: ^1.18.0 + flutter_rating_stars: ^1.1.0 + syncfusion_flutter_calendar: ^27.1.58 + timezone: ^0.9.4 dev_dependencies: diff --git a/web/index.html b/web/index.html index 396594f..fb3ebad 100644 --- a/web/index.html +++ b/web/index.html @@ -98,8 +98,7 @@ - - +