From ea81c2ea972f81e6f51e6ee83dc17f82eedd820c Mon Sep 17 00:00:00 2001 From: Rafael <1024481@stud.hs-mannheim.de> Date: Thu, 9 May 2024 21:55:17 +0200 Subject: [PATCH] onLocationChanged Callback --- ...onSelector.dart => location_selector.dart} | 78 +++++++++++-------- lib/constants.dart | 1 + lib/helper.dart | 18 +++++ lib/models/location.dart | 20 +++++ lib/pages/user_data_page.dart | 24 ++++-- 5 files changed, 104 insertions(+), 37 deletions(-) rename lib/components/{LocationSelector.dart => location_selector.dart} (76%) create mode 100644 lib/helper.dart diff --git a/lib/components/LocationSelector.dart b/lib/components/location_selector.dart similarity index 76% rename from lib/components/LocationSelector.dart rename to lib/components/location_selector.dart index 67fffb1..2069424 100644 --- a/lib/components/LocationSelector.dart +++ b/lib/components/location_selector.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; +import 'package:cofounderella/models/location.dart'; class LocationSelector extends StatefulWidget { - const LocationSelector({super.key}); + final Function(MyLocation) onLocationChanged; // Callback function + + const LocationSelector({super.key, required this.onLocationChanged}); @override LocationSelectorState createState() => LocationSelectorState(); @@ -24,38 +27,38 @@ class LocationSelectorState extends State { @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, - ), - ), + 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'), - ], - ); + ), + ), + 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 { @@ -98,6 +101,17 @@ class LocationSelectorState extends State { _administrativeArea = placeMark.administrativeArea; errorText = null; }); + // location is found, trigger callback + widget.onLocationChanged(MyLocation( + street: _street, + country: _country, + administrativeArea: _administrativeArea, + locality: _city, + subLocality: _subLocality, + postalCode: _postalCode, + latitude: _latitude, + longitude: _longitude, + )); } else { setState(() { // should placeMarks be empty return latitude and longitude anyway diff --git a/lib/constants.dart b/lib/constants.dart index 9aa3a36..dca3823 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -6,6 +6,7 @@ class Constants { static const String dbCollectionUsers = 'Users'; static const String dbCollectionLanguages = 'languages'; + static const String dbCollectionLocations = 'locations'; static const String dbCollectionChatRooms = 'chat_rooms'; static const String dbCollectionMessages = 'messages'; diff --git a/lib/helper.dart b/lib/helper.dart new file mode 100644 index 0000000..b860ff2 --- /dev/null +++ b/lib/helper.dart @@ -0,0 +1,18 @@ +/// Convert decimal coordinate to degrees minutes seconds (DMS) +String convertDecimalToDMS(double decimalValue) { + bool isNegative = decimalValue < 0; + double absoluteValue = decimalValue.abs(); + + int degrees = absoluteValue.toInt(); + double minutesDecimal = (absoluteValue - degrees) * 60; + int minutes = minutesDecimal.toInt(); + double secondsDecimal = (minutesDecimal - minutes) * 60; + double seconds = double.parse(secondsDecimal.toStringAsFixed(2)); + + String direction = isNegative + ? (decimalValue < 0 ? 'W' : 'S') + : (decimalValue >= 0 ? (degrees != 0 ? 'N' : 'E') : ''); + + // return formatted string + return '${degrees.abs()}° ${minutes.abs()}\' ${seconds.abs()}" $direction'; +} \ No newline at end of file diff --git a/lib/models/location.dart b/lib/models/location.dart index 2755119..4d25568 100644 --- a/lib/models/location.dart +++ b/lib/models/location.dart @@ -1,3 +1,5 @@ +import '../helper.dart'; + class MyLocation { final String street; final String country; @@ -37,6 +39,24 @@ class MyLocation { }; } + /// Returns: locality, country. In case of an error: latitude, longitude. + String toStringDegree() { + try { + String latResult = convertDecimalToDMS(latitude!); + String longResult = convertDecimalToDMS(longitude!); + return '$latResult, $longResult'; + } catch (e) { + // on error return origin values + return '$latitude, $longitude'; + } + } + + @override + /// Returns: locality, country + String toString() { + return '$locality, $country'; + } + @override int get hashCode => Object.hash(latitude, longitude); diff --git a/lib/pages/user_data_page.dart b/lib/pages/user_data_page.dart index 9b80b1f..c41acc8 100644 --- a/lib/pages/user_data_page.dart +++ b/lib/pages/user_data_page.dart @@ -4,11 +4,12 @@ import 'package:cofounderella/components/my_button.dart'; import 'package:cofounderella/constants.dart'; import 'package:cofounderella/models/language.dart'; import 'package:cofounderella/models/language_setting.dart'; -import 'package:cofounderella/components/LocationSelector.dart'; +import 'package:cofounderella/components/location_selector.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:cofounderella/services/auth/auth_service.dart'; +import 'package:cofounderella/models/location.dart'; class UserDataPage extends StatefulWidget { const UserDataPage({super.key}); @@ -20,7 +21,7 @@ class UserDataPage extends StatefulWidget { enum Gender { none, male, female, divers } class _UserDataPageState extends State { - + MyLocation? _selectedLocation; List languagesList = []; final List _selectedLanguages = []; @@ -223,10 +224,23 @@ class _UserDataPageState extends State { 'Location', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), - const Padding( - padding: EdgeInsets.all(16.0), - child: LocationSelector(), + Padding( + padding: const EdgeInsets.all(16.0), + child: LocationSelector( + onLocationChanged: (location) { + setState(() { + _selectedLocation = location; + }); + }, + ), ), + // TODO Show and handle selected location + if (_selectedLocation != null) ...[ + Text(style: const TextStyle(backgroundColor: Colors.yellow), + 'Selected Location: ${_selectedLocation!.toString()}'), + Text(style: const TextStyle(backgroundColor: Colors.yellowAccent), + 'Coordinates: ${_selectedLocation!.toStringDegree()}'), + ], const Text( 'Age', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),