import 'package:ambito/src/entity/_general/id_value/id_value.dart'; import 'package:ambito/src/entity/area/area_datasource.dart'; import 'package:ambito/src/entity/area/area_repository.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:google_geocoding_api/google_geocoding_api.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:screen_breakpoints/screen_breakpoints.dart'; import 'package:syncfusion_flutter_core/theme.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:toggle_switch/toggle_switch.dart'; import '../../../config/config.dart'; import '../../../consts/consts.dart'; import '../../../entity/area/area.dart'; import '../../../entity/business/business.dart'; import '../../../packages/ambito_api/base_api.dart'; import '../../../packages/ambito_theme/ambito_theme.dart'; import '../../../widgets/appbar/ambito_appbar.dart'; import '../../../widgets/map/map_widget.dart'; import '../../../widgets/map/marker_generator.dart'; import '../../../widgets/page/base_page.dart'; class DashboardAreasPage extends StatefulWidget { const DashboardAreasPage( {super.key, required this.businessId, required this.userId}); final int businessId; final int userId; @override State createState() => DashboardAreasPageState(); } class DashboardAreasPageState extends State { Widget mapWidget = const SizedBox(); final api = GoogleGeocodingApi(googleApiKey, isLogged: false); Set markers = {}; Set polygons = {}; List areas = []; Business? business; int display = 0; @override void initState() { BaseApi().getContent('business').then((_) { business = isar.business.get(widget.businessId); display = int.tryParse(Get.parameters['index'] ?? '0') ?? 0; api .search(business!.addressComplete!, language: 'de') .then((GoogleGeocodingResponse response) { MarkerGenerator(64) .createBitmapDescriptorFromIconData( Icons.home, Colors.white, const Color(0xFF60845E), const Color(0xff87A34E), ) .then(( BitmapDescriptor bitMapDescriptor, ) { final prettyAddress = response.results.firstOrNull?.mapToPretty(); areas = AreaRepository().getAreasForBusiness(widget.businessId); for (Area area in areas) { final polygon = area.toPolygon(); if (polygon != null) { setState(() { polygons.add(polygon); }); } } setState(() { markers.add( Marker( markerId: MarkerId(business!.name!), position: LatLng( prettyAddress?.latitude ?? 0, prettyAddress?.longitude ?? 0, ), icon: bitMapDescriptor, ), ); mapWidget = MapWidget( markers: markers, polygons: polygons, ); }); }); }); }); super.initState(); } @override Widget build(BuildContext context) { final AmbitoTheme theme = getTheme(context); setState(() {}); areas = AreaRepository().getAreasForBusiness(widget.businessId); return BasePage().getPage( context, SingleChildScrollView( child: Align( alignment: Alignment.topCenter, child: Padding( padding: context.breakpoint.padding, child: SizedBox( width: 1152, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ theme.verticalSpacer, Text( 'Flächen', style: theme.titleMedium, ), theme.verticalSpacer, Row( children: [ ToggleSwitch( initialLabelIndex: display, totalSwitches: 2, minWidth: 200, borderWidth: 1, labels: const ['Karte', 'Liste'], activeBgColor: [theme.currentColorScheme.secondary], borderColor: [theme.currentColorScheme.secondary], inactiveBgColor: Colors.white, activeFgColor: theme.currentColorScheme.onSecondary, customTextStyles: [theme.bodyMedium], onToggle: (index) { setState(() { display = index ?? 0; }); }, ), const Spacer(), OutlinedButton( style: OutlinedButton.styleFrom( minimumSize: const Size(200, 50), shape: RoundedRectangleBorder( side: const BorderSide( color: Colors.blue, width: 1, style: BorderStyle.solid), borderRadius: BorderRadius.circular( 10, ), ), backgroundColor: theme.currentColorScheme.secondary, foregroundColor: theme.currentColorScheme.onSecondary, side: BorderSide( width: 1, color: theme.currentColorScheme.secondary), ), onPressed: () async { final TextEditingController _controllerName = TextEditingController(); final TextEditingController _controllerSize = TextEditingController(); final TextEditingController _controllerDescription = TextEditingController(); await showDialog( context: context, builder: (BuildContext context) => Dialog.fullscreen( child: Scaffold( appBar: AmbitoAppbar( links: const ['dashboard', 'massnahmen'], breakpoint: Breakpoint.fromContext(context), theme: theme), body: BreakpointBuilder( builder: ( context, breakpoint, configuration, ) { return SingleChildScrollView( child: Center( child: SizedBox( width: Breakpoint.fromContext(context) .width, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ theme.verticalSpacer, Text( 'Fläche bearbeiten', style: theme.headlineMedium .copyWith( color: theme .currentColorScheme .onSurface, ), ), theme.verticalSpacer, Align( alignment: Alignment.centerRight, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ OutlinedButton( style: OutlinedButton .styleFrom( minimumSize: const Size( 200, 50), shape: RoundedRectangleBorder( side: BorderSide( color: redColors[ 'primary']!, width: 1, style: BorderStyle .solid, ), borderRadius: BorderRadius .circular( 10, ), ), backgroundColor: theme .currentColorScheme .surface .withOpacity( .1), foregroundColor: theme .currentColorScheme .primary, side: BorderSide( width: 1, color: theme .currentColorScheme .primary, ), ), onPressed: () { Navigator.pop( context); }, child: Text( 'Abbrechen', style: theme .bodyMedium, ), ), theme.horizontalSpacer, OutlinedButton( onHover: (hover) {}, style: OutlinedButton .styleFrom( minimumSize: const Size( 200, 50), shape: RoundedRectangleBorder( side: BorderSide( color: redColors[ 'primary']!, width: 1, style: BorderStyle .solid, ), borderRadius: BorderRadius .circular( 10, ), ), backgroundColor: theme .currentColorScheme .secondary, foregroundColor: theme .currentColorScheme .onPrimary, side: BorderSide( width: 1, color: theme .currentColorScheme .secondary, ), ), onPressed: () async { Area area = Area() ..id = isar.areas .autoIncrement() ..description = _controllerDescription .value .text ..business = [ IdValue() ..id = widget .businessId ..value = business! .name! ] ..name = _controllerName .value .text ..size = _controllerSize .value .text; await BaseApi() .postContent( 'area', area.toJson()); await BaseApi() .getContent( 'business'); setState(() { areas = AreaRepository() .getAreasForBusiness( widget .businessId); logger.d( areas.length); }); Navigator.pop( context); }, child: Text( 'Speichern', style: theme .bodyMedium, ), ), ], ), ), theme.verticalSpacer, Card( elevation: 0, color: theme .currentColorScheme .tertiary, child: Padding( padding: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment .start, children: [ Text( 'Allgemein', style: theme .headlineSmall, ), theme.verticalSpacer, Row( children: [ Expanded( child: TextField( controller: _controllerName, maxLines: 1, decoration: InputDecoration( labelText: 'Bezeichnung', isDense: true, hintText: 'Bezeichnung', filled: true, fillColor: Colors .white, hoverColor: Colors .white, border: OutlineInputBorder( borderSide: BorderSide( color: redColors[ 'primary']!, width: 1, style: BorderStyle .solid, ), borderRadius: BorderRadius.circular( 8), ), ), ), ), theme .horizontalSpacer, Expanded( child: TextField( controller: _controllerSize, maxLines: 1, decoration: InputDecoration( suffixText: 'm²', labelText: 'Größe', isDense: true, hintText: 'Größe', filled: true, fillColor: Colors .white, hoverColor: Colors .white, border: OutlineInputBorder( borderSide: BorderSide( color: redColors[ 'primary']!, width: 1, style: BorderStyle .solid, ), borderRadius: BorderRadius.circular( 8), ), ), ), ), ], ), theme.verticalSpacer, TextField( controller: _controllerDescription, maxLines: 5, decoration: InputDecoration( labelText: 'Notizen', isDense: true, hintText: 'Notizen', filled: true, fillColor: Colors.white, hoverColor: Colors.white, border: OutlineInputBorder( borderSide: BorderSide( color: redColors[ 'primary']!, width: 1, style: BorderStyle .solid, ), borderRadius: BorderRadius .circular( 8), ), ), ), ], ), ), ), theme.verticalSpacer, ], ), ), ), ), ); }, ), ), ), ); Get.offAndToNamed('/dashboard/flaechen/1'); }, child: Text( 'Neue Fläche', style: theme.bodyMedium, )) ], ), theme.verticalSpacer, (display == 0) ? mapWidget : gridWidget(areas), theme.verticalSpacer, ], ), ), ), ), ), ); } Widget gridWidget(List areas) { final AmbitoTheme theme = getTheme(context); return SizedBox( width: 1152, child: SfDataGridTheme( data: SfDataGridThemeData( headerColor: theme.currentColorScheme.primaryContainer, sortIcon: Icon( Icons.keyboard_arrow_down, color: theme.currentColorScheme.primary, ), ), child: SfDataGrid( allowSorting: true, source: AreaDataSource(areas: areas, context: context), columnWidthMode: ColumnWidthMode.fill, columns: [ GridColumn( visible: false, columnName: 'id', label: Container( padding: const EdgeInsets.symmetric(horizontal: 10.0), alignment: Alignment.centerRight, child: Text( 'ID', overflow: TextOverflow.ellipsis, style: theme.bodyMedium.copyWith( color: theme.currentColorScheme.primary, ), ), ), ), GridColumn( columnName: 'name', label: Container( padding: const EdgeInsets.symmetric(horizontal: 10.0), alignment: Alignment.centerLeft, child: Text( 'Bezeichnung', overflow: TextOverflow.ellipsis, style: theme.bodyMedium.copyWith( color: theme.currentColorScheme.primary, ), ), ), ), GridColumn( columnName: 'size', maximumWidth: 200, label: Container( padding: const EdgeInsets.symmetric(horizontal: 10.0), alignment: Alignment.centerLeft, child: Text( 'Größe', overflow: TextOverflow.ellipsis, style: theme.bodyMedium.copyWith( color: theme.currentColorScheme.primary, ), ), ), ), GridColumn( columnName: 'description', maximumWidth: 100, allowSorting: false, label: Container( padding: const EdgeInsets.symmetric(horizontal: 10.0), alignment: Alignment.centerLeft, child: Text( 'Notiz', overflow: TextOverflow.ellipsis, style: theme.bodyMedium.copyWith( color: theme.currentColorScheme.primary, ), ), ), ), GridColumn( columnName: 'action', allowSorting: false, maximumWidth: 150, label: Container( padding: const EdgeInsets.symmetric(horizontal: 10.0), alignment: Alignment.centerLeft, child: Text( 'Aktion', overflow: TextOverflow.ellipsis, style: theme.bodyMedium.copyWith( color: theme.currentColorScheme.primary, ), ), ), ), ], ), ), ); } }