Added LocationSelector. Depends on geolocator, geocoding.

master
Rafael 2024-05-09 13:31:00 +02:00
parent 0149f4b074
commit 2488023aa3
5 changed files with 362 additions and 6 deletions

View File

@ -0,0 +1,196 @@
import 'package:flutter/material.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
class LocationSelector extends StatefulWidget {
const LocationSelector({super.key});
@override
LocationSelectorState createState() => LocationSelectorState();
}
class LocationSelectorState extends State<LocationSelector> {
final TextEditingController _locationController = TextEditingController();
String _street = '';
String _country = '';
String? _administrativeArea; // DE: Bundesland
String _city = '';
String? _subLocality; // DE: Stadtteil
String? _postalCode;
double? _latitude;
double? _longitude;
String? errorText;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
// onSubmitted: (loc) => {_searchLocation2(loc)},
controller: _locationController,
decoration: InputDecoration(
labelText: 'Enter location',
suffixIcon: IconButton(
icon: const Icon(Icons.search),
onPressed: _searchLocation,
),
),
),
Text(
errorText != null ? '$errorText' : '',
style: const TextStyle(color: Colors.red),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _getCurrentLocation,
child: const Text('Use Current Position'),
),
const SizedBox(height: 20),
Text('Country: $_country'),
Text('City: $_city'),
Text('Postal Code: $_postalCode'),
Text('Street: $_street'),
Text('Administrative Area: $_administrativeArea'),
Text('Latitude: $_latitude'),
Text('Longitude: $_longitude'),
],
);
}
void _searchLocation() async {
String locationQuery = _locationController.text;
if (locationQuery.trim().isEmpty) {
setState(() {
errorText = 'Specify an address for the search';
_street = '';
_country = '';
_city = '';
_subLocality = null;
_postalCode = null;
_administrativeArea = null;
_latitude = null;
_longitude = null;
});
return;
}
try {
List<Location> locations = await locationFromAddress(locationQuery);
if (locations.isNotEmpty) {
// Take first match
Location firstLocation = locations.first;
// Extract country and city information
List<Placemark> placeMarks = await placemarkFromCoordinates(
firstLocation.latitude, firstLocation.longitude);
if (placeMarks.isNotEmpty) {
Placemark placeMark = placeMarks.first;
setState(() {
_latitude = firstLocation.latitude;
_longitude = firstLocation.longitude;
_street = '${placeMark.street}';
_country = placeMark.country!;
_city = placeMark.locality!;
_subLocality = placeMark.subLocality;
_postalCode = placeMark.postalCode;
_administrativeArea = placeMark.administrativeArea;
errorText = null;
});
} else {
setState(() {
// should placeMarks be empty return latitude and longitude anyway
_latitude = firstLocation.latitude;
_longitude = firstLocation.longitude;
errorText = null;
});
}
} else {
setState(() {
errorText = 'Location $locationQuery not found';
_street = '';
_country = '';
_city = '';
_subLocality = null;
_postalCode = null;
_administrativeArea = null;
_latitude = null;
_longitude = null;
});
}
} catch (e) {
setState(() {
errorText = 'Error searching location $locationQuery: $e';
_street = '';
_country = '';
_city = '';
_subLocality = null;
_postalCode = null;
_administrativeArea = null;
_latitude = null;
_longitude = null;
});
}
}
/// Determine users position using geolocator package
void _getCurrentLocation() async {
bool serviceEnabled;
LocationPermission permission;
try {
// Test if location services are enabled.
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// Location services are not enabled don't continue
// accessing the position and request users of the
// App to enable the location services.
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
// Permissions are denied, next time you could try
// requesting permissions again (this is also where
// Android's shouldShowRequestPermissionRationale
// returned true. According to Android guidelines
// your App should show an explanatory UI now.
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
// Permissions are denied forever, handle appropriately.
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
} catch (e) {
print('Error getting location permission: $e');
}
try {
// When we reach here, permissions are granted and we can
// continue accessing the position of the device.
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
List<Placemark> placeMarks =
await placemarkFromCoordinates(position.latitude, position.longitude);
if (placeMarks.isNotEmpty) {
Placemark placeMark = placeMarks.first;
setState(() {
_street = placeMark.street!;
_country = placeMark.country!;
_city = placeMark.locality!;
_latitude = position.latitude;
_longitude = position.longitude;
});
}
} catch (e) {
print('Error getting current location: $e');
}
}
}

View File

@ -0,0 +1,48 @@
class MyLocation {
final String street;
final String country;
/// DE: Bundesland
final String? administrativeArea;
/// City
final String locality;
/// DE: Stadtteil
final String? subLocality;
final String? postalCode;
final double? latitude;
final double? longitude;
MyLocation({
required this.street,
required this.country,
required this.administrativeArea,
required this.locality,
required this.subLocality,
required this.postalCode,
required this.latitude,
required this.longitude,
});
// convert to a map
Map<String, dynamic> toMap() {
return {
'street': street,
'country': country,
'administrativeArea': administrativeArea,
'locality': locality,
'subLocality': subLocality,
'postalCode': postalCode,
'latitude': latitude,
'longitude': longitude,
};
}
@override
int get hashCode => Object.hash(latitude, longitude);
@override
bool operator ==(Object other) =>
other is MyLocation &&
latitude == other.latitude &&
longitude == other.longitude;
}

View File

@ -1,10 +1,10 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:cofounderella/components/my_button.dart'; import 'package:cofounderella/components/my_button.dart';
import 'package:cofounderella/components/my_textfield.dart';
import 'package:cofounderella/constants.dart'; import 'package:cofounderella/constants.dart';
import 'package:cofounderella/models/language.dart'; import 'package:cofounderella/models/language.dart';
import 'package:cofounderella/models/language_setting.dart'; import 'package:cofounderella/models/language_setting.dart';
import 'package:cofounderella/components/LocationSelector.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@ -20,7 +20,6 @@ class UserDataPage extends StatefulWidget {
enum Gender { none, male, female, divers } enum Gender { none, male, female, divers }
class _UserDataPageState extends State<UserDataPage> { class _UserDataPageState extends State<UserDataPage> {
final TextEditingController _locationController = TextEditingController();
List<LanguageSetting> languagesList = []; List<LanguageSetting> languagesList = [];
final List<Language> _selectedLanguages = []; final List<Language> _selectedLanguages = [];
@ -224,10 +223,9 @@ class _UserDataPageState extends State<UserDataPage> {
'Location', 'Location',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
), ),
MyTextField( const Padding(
hintText: "Location", padding: EdgeInsets.all(16.0),
obscureText: false, child: LocationSelector(),
controller: _locationController,
), ),
const Text( const Text(
'Age', 'Age',

View File

@ -81,6 +81,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.18.0" version: "1.18.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -145,6 +153,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.16.0" version: "2.16.0"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -176,6 +192,86 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
geocoding:
dependency: "direct main"
description:
name: geocoding
sha256: d580c801cba9386b4fac5047c4c785a4e19554f46be42f4f5e5b7deacd088a66
url: "https://pub.dev"
source: hosted
version: "3.0.0"
geocoding_android:
dependency: transitive
description:
name: geocoding_android
sha256: "1b13eca79b11c497c434678fed109c2be020b158cec7512c848c102bc7232603"
url: "https://pub.dev"
source: hosted
version: "3.3.1"
geocoding_ios:
dependency: transitive
description:
name: geocoding_ios
sha256: "94ddba60387501bd1c11e18dca7c5a9e8c645d6e3da9c38b9762434941870c24"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
geocoding_platform_interface:
dependency: transitive
description:
name: geocoding_platform_interface
sha256: "8c2c8226e5c276594c2e18bfe88b19110ed770aeb7c1ab50ede570be8b92229b"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
geolocator:
dependency: "direct main"
description:
name: geolocator
sha256: "694ec58afe97787b5b72b8a0ab78c1a9244811c3c10e72c4362ef3c0ceb005cd"
url: "https://pub.dev"
source: hosted
version: "11.0.0"
geolocator_android:
dependency: transitive
description:
name: geolocator_android
sha256: "80cd39a94100957431a6dd37cebd686f6d446bbc9a884d90c9a07b34fd28b923"
url: "https://pub.dev"
source: hosted
version: "4.5.5"
geolocator_apple:
dependency: transitive
description:
name: geolocator_apple
sha256: bc2aca02423ad429cb0556121f56e60360a2b7d694c8570301d06ea0c00732fd
url: "https://pub.dev"
source: hosted
version: "2.3.7"
geolocator_platform_interface:
dependency: transitive
description:
name: geolocator_platform_interface
sha256: "009a21c4bc2761e58dccf07c24f219adaebe0ff707abdfd40b0a763d4003fab9"
url: "https://pub.dev"
source: hosted
version: "4.2.2"
geolocator_web:
dependency: transitive
description:
name: geolocator_web
sha256: "49d8f846ebeb5e2b6641fe477a7e97e5dd73f03cbfef3fd5c42177b7300fb0ed"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
geolocator_windows:
dependency: transitive
description:
name: geolocator_windows
sha256: "53da08937d07c24b0d9952eb57a3b474e29aae2abf9dd717f7e1230995f13f0e"
url: "https://pub.dev"
source: hosted
version: "0.2.3"
http: http:
dependency: transitive dependency: transitive
description: description:
@ -309,6 +405,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.10.0"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -357,6 +461,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.3.2"
uuid:
dependency: transitive
description:
name: uuid
sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
url: "https://pub.dev"
source: hosted
version: "4.4.0"
vector_graphics: vector_graphics:
dependency: transitive dependency: transitive
description: description:

View File

@ -40,6 +40,8 @@ dependencies:
cloud_firestore: ^4.17.2 cloud_firestore: ^4.17.2
provider: ^6.1.2 provider: ^6.1.2
flutter_svg: ^2.0.10+1 flutter_svg: ^2.0.10+1
geolocator: ^11.0.0
geocoding: ^3.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: