import 'package:diacritic/diacritic.dart'; import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:location_picker_flutter_map/location_picker_flutter_map.dart'; import 'package:manager_app/Components/geoloc_input_container.dart'; import 'package:manager_app/Components/multi_select_dropdown_language_container.dart'; import 'package:manager_app/Models/managerContext.dart'; import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/category_input_container.dart'; import 'package:manager_app/Components/dropDown_input_container.dart'; import 'package:manager_app/Components/fetch_section_icon.dart'; import 'package:manager_app/Components/resource_input_container.dart'; import 'package:manager_app/Components/multi_select_container.dart'; import 'package:manager_app/Components/single_select_container.dart'; import 'package:manager_app/Components/slider_input_container.dart'; import 'package:manager_app/Components/string_input_container.dart'; import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/showNewOrUpdateGeoPoint.dart'; import 'package:html/parser.dart' show parse; import 'package:manager_app/app_context.dart'; import 'package:manager_app/constants.dart'; import 'package:manager_api_new/api.dart'; import 'dart:convert'; import 'package:provider/provider.dart'; class MapConfig extends StatefulWidget { final String? color; final String? label; final MapDTO initialValue; final ValueChanged onChanged; const MapConfig({ Key? key, this.color, this.label, required this.initialValue, required this.onChanged, }) : super(key: key); @override _MapConfigState createState() => _MapConfigState(); } class _MapConfigState extends State { late MapDTO mapDTO; late List pointsToShow; List? selectedCategories = []; String mapType= "hybrid"; String mapTypeMapBox= "standard"; String filterSearch = ''; @override void initState() { super.initState(); //mapDTO = MapDTO.fromJson(json.decode(widget.initialValue))!; mapDTO = widget.initialValue; pointsToShow = new List.from(mapDTO.points!); mapDTO.points = pointsToShow; pointsToShow.sort((a, b) => a.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase().compareTo(b.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase())); //selectedCategories = mapDTO.categories!.map((categorie) => categorie.label!.firstWhere((element) => element.language == 'FR').value!).toList(); selectedCategories = mapDTO.categories!.map((categorie) => categorie.id!.toString()).toList(); pointsToShow.forEach((pts) { /*if(pts.categorieId == null && pts.categorie != null && mapDTO.categories!.any((e) => e.order == pts.categorie!.order)) { print("SET CATEGORIE ID FOR CAT"); print(pts.categorie); var testCat = mapDTO.categories!.where((c) => c.label![0].value == pts.categorie!.label![0].value); if(testCat.isNotEmpty) { pts.categorieId = testCat.first.id; pts.categorie!.id = testCat.first.id; } else { pts.categorie = null; // Categorie no more existing so we can reset cat } print(pts.categorieId); }*/ }); print(pointsToShow); if(mapDTO.mapType != null) { switch(mapDTO.mapType!.value) { case 0: mapType = "none"; break; case 1: mapType = "normal"; break; case 2: mapType = "satellite"; break; case 3: mapType = "terrain"; break; case 4: mapType = "hybrid"; break; } } if(mapDTO.mapTypeMapbox != null) { switch(mapDTO.mapTypeMapbox!.value) { case 0: mapTypeMapBox = "standard"; break; case 1: mapTypeMapBox = "streets"; break; case 2: mapTypeMapBox = "outdoors"; break; case 3: mapTypeMapBox = "light"; break; case 4: mapTypeMapBox = "dark"; break; case 5: mapTypeMapBox = "satellite"; break; case 6: mapTypeMapBox = "satellite_streets"; break; } } /*print("MAPDTO"); print(mapDTO); print(mapDTO.mapType.toString()); if (mapDTO.mapType == null) { mapDTO.mapType = MapTypeApp.hybrid; }*/ } @override Widget build(BuildContext context) { final appContext = Provider.of(context); Size size = MediaQuery.of(context).size; var mapProviderIn = ""; switch(mapDTO.mapProvider) { case MapProvider.Google : mapProviderIn = "Google"; break; case MapProvider.MapBox : mapProviderIn = "MapBox"; break; default: mapProviderIn = "Google"; break; } return SingleChildScrollView( child: Column( children: [ Container( height: size.height * 0.3, width: double.infinity, child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ SingleSelectContainer( label: "Service :", color: Colors.black, initialValue: mapProviderIn, inputValues: map_providers, onChanged: (String value) { switch(value) { case "Google": mapDTO.mapProvider = MapProvider.Google; break; case "MapBox": mapDTO.mapProvider = MapProvider.MapBox; break; } //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); } ), GeolocInputContainer( label: "Point de centrage:", initialValue: mapDTO.latitude != null && mapDTO.longitude != null ? LatLong(double.parse(mapDTO.latitude!), double.parse(mapDTO.longitude!)) : null, color: kPrimaryColor, onChanged: (LatLong? localisation) { if(localisation != null) { mapDTO.longitude = localisation.longitude.toString(); mapDTO.latitude = localisation.latitude.toString(); } //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); }, isSmall: true ), // Icon ResourceInputContainer( label: "Icône:", initialValue: mapDTO.iconResourceId, color: kPrimaryColor, imageFit: BoxFit.contain, onChanged: (ResourceDTO resource) { if(resource.id == null) { mapDTO.iconSource = null; mapDTO.iconResourceId = null; } else { mapDTO.iconResourceId = resource.id; mapDTO.iconSource = resource.url; } //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); }, isSmall: true ), ] ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ if(mapDTO.mapProvider == MapProvider.Google) // Map Type DropDownInputContainer( label: "Type:", values: map_types, initialValue: mapType, onChange: (String? value) { mapDTO.mapType = MapTypeApp.fromJson(value); //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); }, ), if(mapDTO.mapProvider == MapProvider.MapBox) DropDownInputContainer( label: "Type:", values: map_types_mapBox, initialValue: mapTypeMapBox, onChange: (String? value) { mapDTO.mapTypeMapbox = MapTypeMapBox.fromJson(value); //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); }, ), // Zoom SliderInputContainer( label: "Zoom:", initialValue: mapDTO.zoom != null ? mapDTO.zoom!.toDouble() : 18, color: kPrimaryColor, min: 0, max: 30, onChanged: (double value) { mapDTO.zoom = value.toInt(); //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); }, ), Container( height: 70, child: CategoryInputContainer( label: "Catégories :", initialValue: mapDTO.categories != null ? mapDTO.categories! : [], color: kPrimaryColor, onChanged: (List? value) { if(value != null) { //print("COUCOU CategoryInputContainerCategoryInputContainerCategoryInputContainer"); //print(value); mapDTO.categories = value; //update point's category if(mapDTO.points != null) { mapDTO.points!.forEach((p) { // Check if category still exist - Delete if(p.categorieId != null && !mapDTO.categories!.map((c) => c.id).any((e) => e != null && e == p.categorieId)) { print("DELETE CAT REF"); print(p.categorieId); //print(p.categorie); // delete cat ref from point p.categorieId = null; //p.categorie = null; } // update point category - Update if(p.categorieId != null && mapDTO.categories!.map((c) => c.id).any((e) => e != null && e == p.categorieId)) { var categorie = mapDTO.categories!.firstWhere((c) => c.id == p.categorieId); //p.categorie = categorie; print("UPDATE CAT REF"); } print(p); /*if(p.categorieId == null && p.categorie != null && p.categorie!.label != null) { // need to update with label var categorie = mapDTO.categories!.firstWhere((c) => c.label![0].value == p.categorie!.label![0].value); //p.categorie = categorie; p.categorieId = categorie.id; }*/ }); } /*print("mapDTO.points"); print(mapDTO.points);*/ //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); } }, ), ) ], ), ], ), ), Padding( padding: const EdgeInsets.all(8.0), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), border: Border.all(width: 1.5, color: kSecond) ), child: Stack( children: [ Container( constraints: BoxConstraints(minHeight: 100), child: Padding( padding: const EdgeInsets.only(top: 95, left: 10, right: 10, bottom: 10), child: GridView.builder( shrinkWrap: true, gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 8), itemCount: pointsToShow.length, itemBuilder: (BuildContext context, int index) { return Container( decoration: boxDecoration(pointsToShow[index], appContext), padding: const EdgeInsets.all(5), margin: EdgeInsets.symmetric(vertical: 10, horizontal: 10), child: getElement(index, pointsToShow[index], size, appContext), ); } ), ), ), Positioned( top: 10, left: 10, child: Text( "Points géographiques", style: TextStyle(fontSize: 15), ), ), Positioned( top: 10, left: 175, child: MultiSelectContainer( label: null, color: kSecond, width: size.width * 0.45, initialValue: selectedCategories!, isMultiple: true, isHTMLLabel : true, values: mapDTO.categories!.map((categorie) => categorie.label!.firstWhere((element) => element.language == 'FR').value!).toList(), onChanged: (value) { var tempOutput = new List.from(value); setState(() { selectedCategories = tempOutput; if(selectedCategories == null || selectedCategories!.length == 0) { //pointsToShow = mapDTO.points!.where((point) => point.categorie == null).toList(); pointsToShow = mapDTO.points!.where((point) => point.categorieId == null).toList(); } else { //pointsToShow = mapDTO.points!.where((point) => tempOutput.any((tps) => point.categorie == null || point.categorie?.label?.firstWhere((lab) => lab.language == 'FR').value == tps)).toList(); pointsToShow = mapDTO.points!.where((point) => tempOutput.any((tps) => point.categorieId == null || point.categorieId == tps)).toList(); } }); }, ) ), Positioned( top: 0, right: 150, child: Container( height: size.height*0.1, constraints: BoxConstraints(minHeight: 85), child: StringInputContainer( label: "Recherche:", isSmall: true, fontSize: 15, fontSizeText: 15, onChanged: (String value) { setState(() { filterSearch = value; filterPoints(); }); }, ), ), ), Positioned( top: 10, right: 10, child: InkWell( onTap: () { showNewOrUpdateGeoPoint( mapDTO, null, (GeoPointDTO geoPoint) async { setState(() { mapDTO.points!.add(geoPoint); mapDTO.points!.sort((a, b) => a.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase().compareTo(b.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase())); if(selectedCategories == null || selectedCategories!.length == 0) { //pointsToShow = mapDTO.points!.where((point) => point.categorie == null).toList(); pointsToShow = mapDTO.points!.where((point) => point.categorieId == null).toList(); } else { //pointsToShow = mapDTO.points!.where((point) => selectedCategories!.any((tps) => point.categorie == null || point.categorie?.label?.firstWhere((lab) => lab.language == 'FR').value == tps)).toList(); pointsToShow = mapDTO.points!.where((point) => selectedCategories!.any((tps) => point.categorieId == null || point.categorieId == tps)).toList(); } //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); }); await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionMapApi!.sectionMapCreate(mapDTO.id!, geoPoint); // TODO refresh points list }, appContext, context); }, child: Container( height: MediaQuery.of(context).size.width * 0.04, width: MediaQuery.of(context).size.width * 0.04, child: Icon( Icons.add, color: kTextLightColor, size: 30.0, ), decoration: BoxDecoration( color: kSuccess, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(20.0), boxShadow: [ BoxShadow( color: kSecond, spreadRadius: 0.5, blurRadius: 5, offset: Offset(0, 1.5), // changes position of shadow ), ], ), ), ), ) ]), ), ), ], ), ); } getElement(int index, GeoPointDTO? point, Size size, AppContext appContext) { return Container( width: double.infinity, height: double.infinity, child: Stack( children: [ Center( child: Padding( padding: const EdgeInsets.all(8.0), child: HtmlWidget( point != null ? point.title == null ? "" : point.title![0].value! : "", //textAlign: TextAlign.left, customStylesBuilder: (element) { return {'text-align': 'center'}; }, textStyle: TextStyle(fontSize: 20) ), ), ), Positioned( top: 0, right: 0, child: Icon( getSectionIcon(SectionType.Map), color: kSecond, size: 18.0, ), ), Positioned( bottom: 0, left: 0, child: InkWell( onTap: () { showNewOrUpdateGeoPoint( mapDTO, pointsToShow[index], (GeoPointDTO geoPoint) { setState(() { var pointToUpdate = pointsToShow[index]; var pointToUpdateMapDTOPoints = mapDTO.points!.firstWhere((p) => p.longitude == pointToUpdate.longitude && p.latitude == pointToUpdate.latitude); var mapDTOPointsIndex = mapDTO.points!.indexOf(pointToUpdateMapDTOPoints); mapDTO.points![mapDTOPointsIndex] = pointToUpdate; mapDTO.points!.sort((a, b) => a.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase().compareTo(b.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase())); //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); }); }, appContext, context); }, child: Icon( Icons.edit, color: kPrimaryColor, size: 20.0, ) ), ), Positioned( bottom: 0, right: 0, child: InkWell( onTap: () { setState(() { var pointToRemove = pointsToShow[index]; mapDTO.points = mapDTO.points!.where((p) => p.longitude != pointToRemove.longitude && p.latitude != pointToRemove.latitude).toList(); pointsToShow.removeAt(index); }); //widget.onChanged(jsonEncode(mapDTO).toString()); widget.onChanged(mapDTO); }, child: Icon( Icons.delete, color: kError, size: 20.0, ) ), ) ], ), ); } void filterPoints() { pointsToShow = filterSearch.isEmpty ? mapDTO.points! : mapDTO.points!.where((GeoPointDTO pointGeo) => removeDiacritics(pointGeo.title!.firstWhere((t) => t.language == "FR").value!.toUpperCase()).contains(removeDiacritics(filterSearch.toUpperCase()))).toList(); } } boxDecoration(GeoPointDTO geoPointDTO, appContext) { return BoxDecoration( color: kBackgroundColor, shape: BoxShape.rectangle, border: Border.all(width: 1.5, color: kSecond), borderRadius: BorderRadius.circular(10.0), boxShadow: [ BoxShadow( color: kSecond, spreadRadius: 0.5, blurRadius: 5, offset: Offset(0, 1.5), // changes position of shadow ), ], ); }