import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart' ; import '../../../bloc/device_update_bloc.dart'; import '../../../product/constant/app/app_constants.dart'; import '../../../product/extension/context_extension.dart'; import '../../../product/services/language_services.dart'; import '../../../product/shared/find_location_maps/shared_map_search_location.dart'; import '../../../product/shared/find_location_maps/model/prediction_model.dart'; import '../../../product/shared/shared_transition.dart'; import 'geocode_model.dart'; showMapDialog( BuildContext context, DeviceUpdateBloc deviceUpdateBloc, TextEditingController latitudeController, TextEditingController longitudeController) async { const CameraPosition defaultPosition = CameraPosition( target: LatLng(20.985424, 105.738354), zoom: 12, ); TextEditingController searchLocationController = TextEditingController(); TextEditingController mapDialogLatitudeController = TextEditingController(); TextEditingController mapDialogLongitudeController = TextEditingController(); Completer ggmapController = Completer(); final streamController = StreamController.broadcast(); showGeneralDialog( barrierDismissible: false, transitionDuration: context.normalDuration, transitionBuilder: transitionsLeftToRight, context: context, pageBuilder: (context, animation, secondaryAnimation) { return StreamBuilder>( stream: deviceUpdateBloc.streamMarkers, builder: (context, markerSnapshot) { if (!markerSnapshot.hasData) { if (latitudeController.value.text != "" && longitudeController.value.text != "") { double latitude = double.parse(latitudeController.text); double longitude = double.parse(longitudeController.text); addMarker( LatLng(latitude, longitude), ggmapController, deviceUpdateBloc, mapDialogLatitudeController, mapDialogLongitudeController, ); } } return Scaffold( appBar: AppBar( title: Text(appLocalization(context) .update_device_dialog_maps_dialog_title), centerTitle: true, actions: [ IconButton( onPressed: () async { String latitude = mapDialogLatitudeController.text; String longitude = mapDialogLongitudeController.text; log("Finish -- Latitude: $latitude, longitude: $longitude --"); getDataFromApi(context,latitude, longitude, deviceUpdateBloc); latitudeController.text = mapDialogLatitudeController.text; longitudeController.text = mapDialogLongitudeController.text; bool isChange = true; deviceUpdateBloc.sinkIsChanged.add(isChange); Navigator.of(context).pop(); }, icon: const Icon(Icons.check)) ], ), body: Stack( children: [ GoogleMap( onTap: (location) async { addMarker( location, ggmapController, deviceUpdateBloc, mapDialogLatitudeController, mapDialogLongitudeController, ); }, markers: markerSnapshot.data ?? {}, onMapCreated: (GoogleMapController mapController) { ggmapController.complete(mapController); streamController.add(mapController); }, initialCameraPosition: defaultPosition, ), Container( // color: Colors.white, height: 80, alignment: Alignment.topCenter, padding: const EdgeInsets.all(10), child: StreamBuilder( stream: deviceUpdateBloc.streamSearchLocation, builder: (context, searchLocation) { return NearBySearchSFM( textInputAction: TextInputAction.done, textEditingController: searchLocation.data ?? searchLocationController, googleAPIKey: ApplicationConstants.MAP_KEY, locationLatitude: 20.985424, locationLongitude: 105.738354, radius: 50000, inputDecoration: InputDecoration( hintText: appLocalization(context) .update_device_dialog_search_location_hint, border: InputBorder.none), debounceTime: 600, isLatLngRequired: true, getPlaceDetailWithLatLng: (Prediction prediction) { FocusScope.of(context).unfocus(); addMarker( LatLng(double.parse(prediction.lat!), double.parse(prediction.lng!)), ggmapController, deviceUpdateBloc, mapDialogLatitudeController, mapDialogLongitudeController); }, itemClick: (Prediction prediction) { searchLocationController.text = prediction.structuredFormatting!.mainText!; deviceUpdateBloc.sinkSearchLocation .add(searchLocationController); searchLocationController.selection = TextSelection.fromPosition(TextPosition( offset: prediction.structuredFormatting! .mainText!.length)); }, boxDecoration: BoxDecoration( color: Colors.white, border: Border.all( color: Colors.grey, width: 0.5, ), borderRadius: const BorderRadius.all( Radius.circular(20))), ); }), ) ], ), ); }); }, ); } addMarker( LatLng position, Completer mapController, DeviceUpdateBloc deviceUpdateBloc, TextEditingController mapDialogLatitudeController, TextEditingController mapDialogLongitudeController, ) async { log("AddMarker -- Latitude: ${position.latitude}, longitude: ${position.longitude} --"); Set marker = {}; deviceUpdateBloc.sinkMarkers.add(marker); Marker newMarker = Marker( markerId: const MarkerId('value'), position: LatLng(position.latitude, position.longitude), icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen), draggable: true, onDragEnd: (position) { mapDialogLatitudeController.text = position.latitude.toString(); mapDialogLongitudeController.text = position.longitude.toString(); }, ); marker.add(newMarker); deviceUpdateBloc.sinkMarkers.add(marker); mapDialogLatitudeController.text = position.latitude.toString(); mapDialogLongitudeController.text = position.longitude.toString(); updateCameraPosition(position, 14, mapController); } void getDataFromApi(BuildContext context,String latitude, String longitude, DeviceUpdateBloc deviceUpdateBloc) async { String path = "maps/api/geocode/json?latlng=$latitude,$longitude&language=vi&result_type=political&key=${ApplicationConstants.MAP_KEY}"; var url = Uri.parse('https://maps.googleapis.com/$path'); final response = await http.get(url); if (response.statusCode != 200) { log("Loi: ${response.statusCode}"); return; } Map data = jsonDecode(response.body); if (!data.containsKey('results') || data['results'].isEmpty) { log("Khong co result"); return; } List results = data['results']; List geocodes = results.map((result) => Geocode.fromJson(result)).toList(); Map locations = _extractLocationComponents(geocodes[0].addressComponents!); // In ra thông tin của các location locations.forEach((key, value) { log("$key: $value"); }); await _processLocations(context,locations, deviceUpdateBloc); } Map _extractLocationComponents( List addressComponents) { Map locations = {}; for (var addressComponent in addressComponents) { String longName = addressComponent.longName ?? ""; if (addressComponent.types!.contains('administrative_area_level_3') || addressComponent.types!.contains('sublocality_level_1')) { locations['wardkey'] = longName; } else if (addressComponent.types! .contains('administrative_area_level_2') || addressComponent.types!.contains('sublocality_level_2') || addressComponent.types!.contains('locality')) { locations['districtkey'] = longName; } else if (addressComponent.types! .contains('administrative_area_level_1')) { locations['provincekey'] = longName; } } return locations; } Future _processLocations(BuildContext context, Map locations, DeviceUpdateBloc deviceUpdateBloc) async { String provinceNameFromAPI = locations['provincekey'] ?? ""; String districtNameFromAPI = locations['districtkey'] ?? ""; String wardNameFromAPI = locations['wardkey'] ?? ""; final province = await deviceUpdateBloc.getProvinceByName(context,provinceNameFromAPI); if (province.name != "null") { log("Province: ${province.fullName}, ProvinceCode: ${province.code}"); deviceUpdateBloc.sinkProvinceData .add({"code": province.code!, "name": province.fullName!}); deviceUpdateBloc.getAllProvinces(context); final district = await deviceUpdateBloc.getDistrictByName(context, districtNameFromAPI, province.code!); log("Districtname: ${district.fullName}, districtCode: ${district.code}"); deviceUpdateBloc.getAllDistricts(context,province.code!); if (district.name != "null") { deviceUpdateBloc.sinkDistrictData .add({"code": district.code!, "name": district.fullName!}); final ward = await deviceUpdateBloc.getWardByName(context,wardNameFromAPI, district.code!); log("Wardname: ${ward.fullName}, WardCode: ${ward.code}"); deviceUpdateBloc.getAllWards(context,district.code!); if (ward.name != "null") { log("Xac dinh duoc het thong tin tu toa do"); deviceUpdateBloc.sinkWardData .add({"code": ward.code!, "name": ward.fullName!}); } else { deviceUpdateBloc.sinkWardData.add({}); } } else { deviceUpdateBloc.sinkDistrictData.add({}); } } else { deviceUpdateBloc.sinkProvinceData.add({}); } } Future updateCameraPosition(LatLng location, double zoom, Completer mapController) async { final CameraPosition cameraPosition = CameraPosition( target: LatLng( location.latitude, location.longitude, ), zoom: zoom, ); final GoogleMapController mapControllerNew = await mapController.future; mapControllerNew.animateCamera( CameraUpdate.newCameraPosition( cameraPosition, ), ); }