From ca17307abd1caa5b9fd7f0775363f6cb548740d7 Mon Sep 17 00:00:00 2001 From: Rolin Bos Date: Fri, 6 Mar 2026 16:51:39 +0100 Subject: [PATCH 1/2] WIP --- geocoding_android/example/lib/main.dart | 454 +++++++++++++++--------- 1 file changed, 291 insertions(+), 163 deletions(-) diff --git a/geocoding_android/example/lib/main.dart b/geocoding_android/example/lib/main.dart index 8eccd77..6296299 100644 --- a/geocoding_android/example/lib/main.dart +++ b/geocoding_android/example/lib/main.dart @@ -1,12 +1,8 @@ +import 'dart:async'; + import 'package:baseflow_plugin_template/baseflow_plugin_template.dart'; import 'package:flutter/material.dart'; -import 'package:geocoding_android/geocoding_android.dart'; - -/// Defines the main theme color. -final MaterialColor themeMaterialColor = - BaseflowPluginExample.createMaterialColor( - const Color.fromRGBO(48, 49, 60, 1), - ); +import 'package:geocoding_android/geocoder.dart'; void main() { runApp(const GeocodeWidget()); @@ -30,25 +26,89 @@ class _GeocodeWidgetState extends State { final TextEditingController _addressController = TextEditingController(); final TextEditingController _latitudeController = TextEditingController(); final TextEditingController _longitudeController = TextEditingController(); + final TextEditingController _lowerLeftLatitudeBoundController = + TextEditingController(); + final TextEditingController _lowerLeftLongitudeBoundController = + TextEditingController(); + final TextEditingController _upperRightLatitudeBoundController = + TextEditingController(); + final TextEditingController _upperRightLongitudeBoundController = + TextEditingController(); String _output = ''; - Locale? _locale; - final Geocoding _geocoding = GeocodingAndroidFactory().createGeocoding( - GeocodingAndroidCreationParams(), - ); + String? _locale; + + (Geocoder, GeocodeListener) _createGeocoderWithListener() { + final geocoderInstance = Geocoder( + locale: Locale( + identifier: _locale ?? Localizations.localeOf(context).toString(), + ), + ); + + final listener = GeocodeListener( + onGeocode: (GeocodeListener listener, List addresses) { + _buildOutputFromAddresses(addresses); + }, + onError: (GeocodeListener instance, String? errorMessage) { + setState(() { + _output = 'Error: ${errorMessage ?? "Unknown error"}'; + }); + }, + ); + + return (geocoderInstance, listener); + } @override void initState() { + super.initState(); + _addressController.text = 'Gronausestraat 710, Enschede'; _latitudeController.text = '52.2165157'; _longitudeController.text = '6.9437819'; + _lowerLeftLatitudeBoundController.text = '52.21514'; + _lowerLeftLongitudeBoundController.text = '6.94417'; + _upperRightLatitudeBoundController.text = '52.21814'; + _upperRightLongitudeBoundController.text = '6.94817'; + } - super.initState(); + Future _buildOutputFromAddresses(List addresses) async { + final buffer = StringBuffer(); + + for (int i = 0; i < addresses.length; i++) { + final address = addresses[i]; + if (address == null) continue; + + final addressLine = await address.getAddressLine(0); + final locality = await address.getLocality(); + final adminArea = await address.getAdminArea(); + final countryName = await address.getCountryName(); + final postalCode = await address.getPostalCode(); + final lat = await address.getLatitude(); + final lng = await address.getLongitude(); + + buffer.writeln('--- Address ${i + 1} ---'); + buffer.writeln(' Address line: $addressLine'); + buffer.writeln(' Locality: $locality'); + buffer.writeln(' Admin area: $adminArea'); + buffer.writeln(' Country: $countryName'); + buffer.writeln(' Postal code: $postalCode'); + buffer.writeln(' Lat/Lng: $lat, $lng'); + buffer.writeln(); + } + + if (buffer.isEmpty) { + buffer.write('No results found.'); + } + + setState(() { + _output = buffer.toString(); + }); } @override Widget build(BuildContext context) { return BaseflowPluginExample( - pluginName: 'geocoding_darwin', + pluginName: 'geocoding_android', githubURL: 'https://github.com/Baseflow/flutter-geocoding', pubDevURL: 'https://pub.dev/packages/geocoding', pages: [ @@ -61,140 +121,23 @@ class _GeocodeWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - DropdownMenu( - leadingIcon: Icon(Icons.language, color: Colors.white), - hintText: 'Locale', - initialSelection: Localizations.localeOf(context), - dropdownMenuEntries: >[ - DropdownMenuEntry( - value: Localizations.localeOf(context), - label: 'Default locale', - ), - DropdownMenuEntry( - value: Locale('en_US'), - label: 'English (US)', - ), - DropdownMenuEntry( - value: Locale('nl_NL'), - label: 'Nederlands (NL)', - ), - ], - onSelected: (Locale? value) => - setState(() => _locale = value), - ), - ], - ), + _languageSelector(context), const Padding(padding: EdgeInsets.only(top: 32)), - Row( - children: [ - Expanded( - child: TextField( - autocorrect: false, - controller: _latitudeController, - style: Theme.of(context).textTheme.bodyMedium, - decoration: const InputDecoration( - hintText: 'Latitude', - ), - keyboardType: TextInputType.number, - ), - ), - const SizedBox(width: 20), - Expanded( - child: TextField( - autocorrect: false, - controller: _longitudeController, - style: Theme.of(context).textTheme.bodyMedium, - decoration: const InputDecoration( - hintText: 'Longitude', - ), - keyboardType: TextInputType.number, - ), - ), - ], - ), - const Padding(padding: EdgeInsets.only(top: 8)), - Center( - child: ElevatedButton( - child: const Text('Look up address'), - onPressed: () { - final latitude = double.parse(_latitudeController.text); - final longitude = double.parse( - _longitudeController.text, - ); - - _geocoding - .placemarkFromCoordinates( - latitude, - longitude, - locale: _locale, - ) - .then((placemarks) { - var output = 'No results found.'; - if (placemarks.isNotEmpty) { - output = placemarks[0].toDisplayString(); - } - - setState(() { - _output = output; - }); - }); - }, - ), - ), + _isPresent(), const Padding(padding: EdgeInsets.only(top: 32)), - TextField( - autocorrect: false, - controller: _addressController, - style: Theme.of(context).textTheme.bodyMedium, - decoration: const InputDecoration(hintText: 'Address'), - keyboardType: TextInputType.text, - ), - const Padding(padding: EdgeInsets.only(top: 8)), - Center( - child: ElevatedButton( - child: const Text('Look up location'), - onPressed: () { - _geocoding - .locationFromAddress(_addressController.text) - .then((locations) { - var output = 'No results found.'; - if (locations.isNotEmpty) { - output = locations[0].toDisplayString(); - } - - setState(() { - _output = output; - }); - }); - }, - ), - ), - const Padding(padding: EdgeInsets.only(top: 8)), - Center( - child: ElevatedButton( - child: const Text('Is present'), - onPressed: () { - _geocoding.isPresent().then((isPresent) { - var output = isPresent - ? "Geocoder is present" - : "Geocoder is not present"; - setState(() { - _output = output; - }); - }); - }, - ), - ), - const Padding(padding: EdgeInsets.only(top: 8)), + _getFromLocation(context), + const Padding(padding: EdgeInsets.only(top: 32)), + _getFromLocationName(context), + const Padding(padding: EdgeInsets.only(top: 16)), + // -- Output display -- Expanded( child: SingleChildScrollView( child: SizedBox( width: MediaQuery.of(context).size.width, - child: Text(_output), + child: Text( + _output, + style: Theme.of(context).textTheme.bodyMedium, + ), ), ), ), @@ -206,30 +149,215 @@ class _GeocodeWidgetState extends State { ], ); } -} -extension _PlacemarkExtensions on Placemark { - String toDisplayString() { - return ''' - Name: $name, - Street: $street, - ISO Country Code: $isoCountryCode, - Country: $country, - Postal code: $postalCode, - Administrative area: $administrativeArea, - Subadministrative area: $subAdministrativeArea, - Locality: $locality, - Sublocality: $subLocality, - Thoroughfare: $thoroughfare, - Subthoroughfare: $subThoroughfare'''; + Widget _languageSelector(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + DropdownMenu( + leadingIcon: Icon(Icons.language, color: Colors.white), + hintText: 'Locale', + initialSelection: Localizations.localeOf(context).toString(), + dropdownMenuEntries: >[ + DropdownMenuEntry( + value: Localizations.localeOf(context).toString(), + label: 'Default locale', + ), + DropdownMenuEntry(value: 'US', label: 'English (US)'), + DropdownMenuEntry(value: 'NL', label: 'Nederlands (NL)'), + ], + onSelected: (String? value) => setState(() => _locale = value), + ), + ], + ); } -} -extension _LocationExtensions on Location { - String toDisplayString() { - return ''' - Latitude: $latitude, - Longitude: $longitude, - Timestamp: $timestamp'''; + Widget _isPresent() { + final isPresent = Geocoder.isPresent(); + + return FutureBuilder( + future: isPresent.then( + (present) => Text( + 'Is geocoder present on this device? ${present ? "Yes" : "No"}', + ), + ), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const CircularProgressIndicator(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return snapshot.data!; + } + }, + ); + } + + Widget _getFromLocation(BuildContext context) { + return Column( + children: [ + Row( + children: [ + Expanded( + child: TextField( + autocorrect: false, + controller: _latitudeController, + style: Theme.of(context).textTheme.bodyMedium, + decoration: const InputDecoration(hintText: 'Latitude'), + keyboardType: TextInputType.number, + ), + ), + const SizedBox(width: 20), + Expanded( + child: TextField( + autocorrect: false, + controller: _longitudeController, + style: Theme.of(context).textTheme.bodyMedium, + decoration: const InputDecoration(hintText: 'Longitude'), + keyboardType: TextInputType.number, + ), + ), + ], + ), + const Padding(padding: EdgeInsets.only(top: 8)), + Center( + child: ElevatedButton( + child: const Text('Look up address'), + onPressed: () { + final latitude = double.parse(_latitudeController.text); + final longitude = double.parse(_longitudeController.text); + + setState(() => _output = 'Loading...'); + + final (geocoderInstance, listener) = + _createGeocoderWithListener(); + + /// If you're on Pre Android API 33, you need to use getFromLocationPreAndroidApi33. + geocoderInstance.getFromLocation( + latitude, + longitude, + 5, + listener, + ); + }, + ), + ), + ], + ); + } + + Widget _getFromLocationName(BuildContext context) { + return Column( + children: [ + TextField( + autocorrect: false, + controller: _addressController, + style: Theme.of(context).textTheme.bodyMedium, + decoration: const InputDecoration(hintText: 'Address'), + keyboardType: TextInputType.text, + ), + Row( + children: [ + Expanded( + child: TextField( + autocorrect: false, + controller: _lowerLeftLatitudeBoundController, + style: Theme.of(context).textTheme.bodyMedium, + decoration: const InputDecoration( + hintText: 'Lower left latitude bound', + ), + keyboardType: TextInputType.number, + ), + ), + const SizedBox(width: 20), + Expanded( + child: TextField( + autocorrect: false, + controller: _lowerLeftLongitudeBoundController, + style: Theme.of(context).textTheme.bodyMedium, + decoration: const InputDecoration( + hintText: 'Lower left longitude bound', + ), + keyboardType: TextInputType.number, + ), + ), + ], + ), + Row( + children: [ + Expanded( + child: TextField( + autocorrect: false, + controller: _upperRightLatitudeBoundController, + style: Theme.of(context).textTheme.bodyMedium, + decoration: const InputDecoration( + hintText: 'Upper right latitude bound', + ), + keyboardType: TextInputType.number, + ), + ), + const SizedBox(width: 20), + Expanded( + child: TextField( + autocorrect: false, + controller: _upperRightLongitudeBoundController, + style: Theme.of(context).textTheme.bodyMedium, + decoration: const InputDecoration( + hintText: 'Upper right longitude bound', + ), + keyboardType: TextInputType.number, + ), + ), + ], + ), + const Padding(padding: EdgeInsets.only(top: 8)), + Center( + child: ElevatedButton( + child: const Text('Look up location'), + onPressed: () { + setState(() => _output = 'Loading...'); + + final lowerLeftLatitude = double.parse( + _lowerLeftLatitudeBoundController.text, + ); + final lowerLeftLongitude = double.parse( + _lowerLeftLongitudeBoundController.text, + ); + final upperRightLatitude = double.parse( + _upperRightLatitudeBoundController.text, + ); + final upperRightLongitude = double.parse( + _upperRightLongitudeBoundController.text, + ); + + final (geocoderInstance, listener) = + _createGeocoderWithListener(); + + /// If you're on Pre Android API 33, you need to use getFromLocationNamePreAndroidApi33. + geocoderInstance.getFromLocationName( + _addressController.text, + 5, + listener, + GeographicBounds( + lowerLeftLatitude: lowerLeftLatitude, + lowerLeftLongitude: lowerLeftLongitude, + upperRightLatitude: upperRightLatitude, + upperRightLongitude: upperRightLongitude, + ), + ); + }, + ), + ), + ], + ); } } + +// Only take a look at the geocoder.dart inside the pigeons folder. + +// getFromLocationName + +// isPresent + +// GeographicBounds From 7fb71a97364b42ff77965b49b7939243ec5c354a Mon Sep 17 00:00:00 2001 From: Rolin Bos Date: Fri, 6 Mar 2026 17:08:20 +0100 Subject: [PATCH 2/2] WIP --- geocoding_android/example/lib/main.dart | 41 +++++++++++-------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/geocoding_android/example/lib/main.dart b/geocoding_android/example/lib/main.dart index 6296299..942bc1b 100644 --- a/geocoding_android/example/lib/main.dart +++ b/geocoding_android/example/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:ui' as ui; import 'package:baseflow_plugin_template/baseflow_plugin_template.dart'; import 'package:flutter/material.dart'; @@ -40,7 +41,8 @@ class _GeocodeWidgetState extends State { (Geocoder, GeocodeListener) _createGeocoderWithListener() { final geocoderInstance = Geocoder( locale: Locale( - identifier: _locale ?? Localizations.localeOf(context).toString(), + identifier: + _locale ?? ui.PlatformDispatcher.instance.locale.languageCode, ), ); @@ -62,13 +64,13 @@ class _GeocodeWidgetState extends State { void initState() { super.initState(); - _addressController.text = 'Gronausestraat 710, Enschede'; + _addressController.text = 'Gronausestraat'; _latitudeController.text = '52.2165157'; _longitudeController.text = '6.9437819'; - _lowerLeftLatitudeBoundController.text = '52.21514'; - _lowerLeftLongitudeBoundController.text = '6.94417'; - _upperRightLatitudeBoundController.text = '52.21814'; - _upperRightLongitudeBoundController.text = '6.94817'; + _lowerLeftLatitudeBoundController.text = '52.207778'; + _lowerLeftLongitudeBoundController.text = '6.925356'; + _upperRightLatitudeBoundController.text = '52.224816'; + _upperRightLongitudeBoundController.text = '6.979773'; } Future _buildOutputFromAddresses(List addresses) async { @@ -87,13 +89,12 @@ class _GeocodeWidgetState extends State { final lng = await address.getLongitude(); buffer.writeln('--- Address ${i + 1} ---'); - buffer.writeln(' Address line: $addressLine'); - buffer.writeln(' Locality: $locality'); - buffer.writeln(' Admin area: $adminArea'); - buffer.writeln(' Country: $countryName'); - buffer.writeln(' Postal code: $postalCode'); - buffer.writeln(' Lat/Lng: $lat, $lng'); - buffer.writeln(); + buffer.writeln('Address line: $addressLine'); + buffer.writeln('Locality: $locality'); + buffer.writeln('Admin area: $adminArea'); + buffer.writeln('Country: $countryName'); + buffer.writeln('Postal code: $postalCode'); + buffer.writeln('Lat/Lng: $lat, $lng'); } if (buffer.isEmpty) { @@ -164,8 +165,8 @@ class _GeocodeWidgetState extends State { value: Localizations.localeOf(context).toString(), label: 'Default locale', ), - DropdownMenuEntry(value: 'US', label: 'English (US)'), - DropdownMenuEntry(value: 'NL', label: 'Nederlands (NL)'), + DropdownMenuEntry(value: 'en', label: 'English (US)'), + DropdownMenuEntry(value: 'nl', label: 'Nederlands (NL)'), ], onSelected: (String? value) => setState(() => _locale = value), ), @@ -257,6 +258,7 @@ class _GeocodeWidgetState extends State { decoration: const InputDecoration(hintText: 'Address'), keyboardType: TextInputType.text, ), + const Padding(padding: EdgeInsets.only(top: 8)), Row( children: [ Expanded( @@ -284,6 +286,7 @@ class _GeocodeWidgetState extends State { ), ], ), + const Padding(padding: EdgeInsets.only(top: 8)), Row( children: [ Expanded( @@ -353,11 +356,3 @@ class _GeocodeWidgetState extends State { ); } } - -// Only take a look at the geocoder.dart inside the pigeons folder. - -// getFromLocationName - -// isPresent - -// GeographicBounds