From 799d1cb335a5ecd32e0154de3e950f13b7bc57ae Mon Sep 17 00:00:00 2001 From: bytedream Date: Wed, 27 Mar 2024 02:32:05 +0100 Subject: [PATCH] added search functionality --- lib/state/mapState.dart | 8 +++++ lib/view/home.dart | 14 +++++++-- lib/view/locationSearch.dart | 60 ++++++++++++++++++++++++++++++++++++ lib/view/map.dart | 15 ++++++++- pubspec.lock | 8 +++++ pubspec.yaml | 1 + 6 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 lib/view/locationSearch.dart diff --git a/lib/state/mapState.dart b/lib/state/mapState.dart index 945733b..69a6e90 100644 --- a/lib/state/mapState.dart +++ b/lib/state/mapState.dart @@ -1,16 +1,24 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:geolocator/geolocator.dart'; +import 'package:latlong2/latlong.dart'; class MapState extends ChangeNotifier { bool _isCurrentlyLoading = false; + LatLng? _activeMarker; final MapController _mapController = MapController(); final Geolocator _geolocator = Geolocator(); bool get isCurrentlyLoading => _isCurrentlyLoading; + LatLng? get getActiveMarker => _activeMarker; MapController get getMapController => _mapController; Geolocator get getGeolocator => _geolocator; + void setActiveMarker(LatLng? marker) { + _activeMarker = marker; + notifyListeners(); + } + void setLoading(bool loading) { _isCurrentlyLoading = loading; notifyListeners(); diff --git a/lib/view/home.dart b/lib/view/home.dart index 15a1e2a..751b6ba 100644 --- a/lib/view/home.dart +++ b/lib/view/home.dart @@ -4,9 +4,11 @@ import 'package:app/state/timeStatusState.dart'; import 'package:app/util/loadingContainer.dart'; import 'package:app/util/watchState.dart'; import 'package:app/view/appInfo.dart'; +import 'package:app/view/locationSearch.dart'; import 'package:app/view/status.dart'; import 'package:app/view/map.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; import 'package:geolocator/geolocator.dart'; import 'package:latlong2/latlong.dart'; import 'package:provider/provider.dart'; @@ -52,8 +54,16 @@ class _HomePageState extends State { actions: [ IconButton( icon: const Icon(Icons.search), - onPressed: () { - + onPressed: () async { + LatLng? latLng = await showSearch( + context: context, + delegate: LocationSearchDelegate(), + ); + MapState mapState = context.obtainState(); + mapState.setActiveMarker(latLng); + if (latLng != null) { + mapState.getMapController.move(latLng, 16); + } }, ), IconButton( diff --git a/lib/view/locationSearch.dart b/lib/view/locationSearch.dart new file mode 100644 index 0000000..e79a295 --- /dev/null +++ b/lib/view/locationSearch.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:osm_nominatim/osm_nominatim.dart'; + +class LocationSearchDelegate extends SearchDelegate { + @override + List? buildActions(BuildContext context) { + return [ + IconButton( + icon: const Icon(Icons.clear), + onPressed: () => query = '', + ) + ]; + } + + @override + Widget? buildLeading(BuildContext context) { + return IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => close(context, null), + ); + } + + @override + Widget buildResults(BuildContext context) { + return FutureBuilder>( + future: query.isEmpty ? Future.value([]) : Nominatim.searchByName( + query: query, + limit: 10, + language: 'de', + // https://gist.github.com/graydon/11198540#file-country-bounding-boxes-py-L45 + viewBox: ViewBox(54.983104153, 15.0169958839, 47.3024876979, 5.98865807458) + ), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return const Center(child: CircularProgressIndicator()); + case ConnectionState.active: + case ConnectionState.none: + case ConnectionState.done: + return ListView.builder( + itemCount: snapshot.data?.length ?? 0, + itemBuilder: (context, index) { + Place place = snapshot.data![index]; + return ListTile( + title: Text(place.displayName), + onTap: () => close(context, LatLng(place.lat, place.lon)), + ); + }, + ); + } + }, + ); + } + + @override + Widget buildSuggestions(BuildContext context) { + return buildResults(context); + } +} diff --git a/lib/view/map.dart b/lib/view/map.dart index 9659974..e52584d 100644 --- a/lib/view/map.dart +++ b/lib/view/map.dart @@ -1,5 +1,6 @@ import 'package:app/extensions/obtainProviderExtension.dart'; import 'package:app/state/mapState.dart'; +import 'package:app/util/watchState.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:http/http.dart'; @@ -36,7 +37,19 @@ class _MapViewState extends State { Client(), when: (response) => response.statusCode == 502) ), - ) + ), + WatchState((context, state) => state.getActiveMarker != null ? MarkerLayer( + markers: [ + Marker( + point: state.getActiveMarker!, + child: const Icon( + Icons.location_on, + color: Colors.red, + size: 48, + ) + ) + ], + ) : const SizedBox.shrink()) ], ); } diff --git a/pubspec.lock b/pubspec.lock index 4769651..a82d0ed 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -384,6 +384,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + osm_nominatim: + dependency: "direct main" + description: + name: osm_nominatim + sha256: "037f1af3abee92cf34e33b562cec1acbb0210234b1bdf3d8975bdef3849e6287" + url: "https://pub.dev" + source: hosted + version: "3.0.0" path: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 990f68f..555e242 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: http: ^1.2.1 flutter_timer_countdown: ^1.0.7 geolocator: ^11.0.0 + osm_nominatim: ^3.0.0 dev_dependencies: flutter_test: