From 5f48de6027b90997eea656148a57d25e8dca4d4d Mon Sep 17 00:00:00 2001 From: Jonasz Bigda Date: Sat, 5 Dec 2020 19:42:20 +0100 Subject: [PATCH] Google Maps | Geo Search | unfinished --- android/app/src/main/AndroidManifest.xml | 2 + lib/components/dishView.dart | 107 ++++++++++++---------- lib/components/homeScreen.dart | 4 +- lib/components/iconChip.dart | 43 +++++++++ lib/components/mapView.dart | 110 +++++++++++++++++++++++ lib/components/mapWithMarkers.dart | 10 --- lib/components/restaurantMapView.dart | 62 +++++++++++++ lib/components/restaurantView.dart | 12 ++- lib/components/searchBar.dart | 1 - lib/services.dart | 73 ++++++++++++++- pubspec.lock | 30 ++++++- pubspec.yaml | 1 + 12 files changed, 390 insertions(+), 65 deletions(-) create mode 100644 lib/components/iconChip.dart create mode 100644 lib/components/mapView.dart delete mode 100644 lib/components/mapWithMarkers.dart create mode 100644 lib/components/restaurantMapView.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 324468b..8a3d44a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -48,5 +48,7 @@ + diff --git a/lib/components/dishView.dart b/lib/components/dishView.dart index bcb479e..7351689 100644 --- a/lib/components/dishView.dart +++ b/lib/components/dishView.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:menui_mobile/services.dart'; import 'lineOfAllergens.dart'; +import 'iconChip.dart'; class DishView extends StatelessWidget { final Dish dish; @@ -22,6 +23,7 @@ class DishView extends StatelessWidget { fit: BoxFit.cover), ), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 160, @@ -32,14 +34,21 @@ class DishView extends StatelessWidget { decoration: BoxDecoration( color: Colors.grey[850], borderRadius: BorderRadius.all(Radius.circular(8))), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Row( + mainAxisSize: MainAxisSize.min, children: [ + Icon( + Icons.restaurant, + color: Colors.orange, + ), + SizedBox( + width: 8, + ), Text( dish.name, style: TextStyle( fontSize: 24, - color: Colors.orange, + color: Colors.white, fontWeight: FontWeight.w300), ), ], @@ -50,26 +59,29 @@ class DishView extends StatelessWidget { ), ), SizedBox(height: 8), + Text( + 'Może zawierać', + style: TextStyle(color: Colors.orange, fontSize: 14), + ), Allergens(allergens: dish.allergens), Divider( height: 14, thickness: 4, ), - Text( - 'Cena', - style: TextStyle(color: Colors.orange, fontSize: 14), - ), SizedBox( - height: 12, + height: 8, ), Prices(prices: dish.prices), SizedBox( - height: 12, + height: 8, ), Divider( height: 14, thickness: 4, ), + SizedBox( + height: 6, + ), Text( 'Składniki', style: TextStyle(color: Colors.orange, fontSize: 14), @@ -82,46 +94,27 @@ class DishView extends StatelessWidget { style: TextStyle(color: Colors.grey[200], fontSize: 12), ), SizedBox( - height: 12, + height: 6, ), - Text( - 'Porcja', - style: TextStyle(color: Colors.orange, fontSize: 14), + Divider( + height: 14, + thickness: 4, ), SizedBox( - height: 12, + height: 6, ), - Text( - '${dish.weight}', - style: TextStyle(color: Colors.grey[200], fontSize: 12), - ), - SizedBox( - height: 12, - ), - Text( - 'Wartość energetyczna', - style: TextStyle(color: Colors.orange, fontSize: 14), - ), - SizedBox( - height: 12, - ), - Text( - '${dish.kCal}', - style: TextStyle(color: Colors.grey[200], fontSize: 12), - ), - SizedBox( - height: 12, - ), - Text( - 'Indeks glikemiczny', - style: TextStyle(color: Colors.orange, fontSize: 14), - ), - SizedBox( - height: 12, - ), - Text( - '${dish.glicemicIndex}', - style: TextStyle(color: Colors.grey[200], fontSize: 12), + Wrap( + spacing: 10, + children: [ + IconChip( + icon: Icons.battery_charging_full, + leading: "Wartość energetyczna", + value: dish.kCal), + IconChip( + icon: Icons.cake, + leading: "Indeks glikemiczny", + value: dish.glicemicIndex), + ], ), SizedBox( height: 12, @@ -133,10 +126,26 @@ class DishView extends StatelessWidget { SizedBox( height: 12, ), - Text( - '${dish.notes}', - style: TextStyle(color: Colors.grey[200], fontSize: 12), - ), + if (dish.notes == "") + Text( + '---', + style: TextStyle(color: Colors.grey[200], fontSize: 12), + ), + if (dish.notes != "") + Text( + '${dish.notes}', + style: TextStyle(color: Colors.grey[200], fontSize: 12), + ), + if (dish.vegan) + Text( + 'Danie wegańskie', + style: TextStyle(color: Colors.grey[200], fontSize: 12), + ), + if (dish.vegetarian) + Text( + 'Danie wegetariańskie', + style: TextStyle(color: Colors.grey[200], fontSize: 12), + ), ], ), ), diff --git a/lib/components/homeScreen.dart b/lib/components/homeScreen.dart index 65d8661..20b1d7c 100644 --- a/lib/components/homeScreen.dart +++ b/lib/components/homeScreen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'searchBar.dart'; import '../settings.dart'; +import 'mapView.dart'; class HomePage extends StatelessWidget { final MenuiSettings settings = new MenuiSettings(); @@ -27,7 +28,8 @@ class HomePage extends StatelessWidget { ), RaisedButton.icon( color: Colors.grey[850], - onPressed: () {}, + onPressed: () => Navigator.push(context, + MaterialPageRoute(builder: (context) => MapView())), icon: Icon( Icons.my_location, color: Colors.orange, diff --git a/lib/components/iconChip.dart b/lib/components/iconChip.dart new file mode 100644 index 0000000..a22111a --- /dev/null +++ b/lib/components/iconChip.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +class IconChip extends StatelessWidget { + final IconData icon; + final String leading; + final String value; + + IconChip({@required this.icon, @required this.leading, @required this.value}); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey[800], + borderRadius: BorderRadius.all(Radius.circular(12))), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + icon, + color: Colors.orange, + ), + SizedBox(height: 8), + Text( + '$leading', + style: TextStyle(color: Colors.grey[300], fontSize: 11), + ), + SizedBox(height: 4), + if (value == "") + Text( + 'brak danych :(', + style: TextStyle(color: Colors.white, fontSize: 14), + ), + if (value != "") + Text( + '$value', + style: TextStyle(color: Colors.white, fontSize: 14), + ), + ]), + ); + } +} diff --git a/lib/components/mapView.dart b/lib/components/mapView.dart new file mode 100644 index 0000000..58b5ef9 --- /dev/null +++ b/lib/components/mapView.dart @@ -0,0 +1,110 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import '../services.dart'; +import 'package:geolocator/geolocator.dart'; + +class MapView extends StatefulWidget { + @override + State createState() => MapViewState(); +} + +class MapViewState extends State { + Completer _controller = Completer(); + MenuiServices services = new MenuiServices(); + Position position; + + Future> createMarkers() async { + Map markers = {}; + Position position = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high); + setState(() { + position = position; + }); + print('position is set'); + /* List restaurants = await services.fetchRestaurantsByLocation( + position.latitude, position.longitude, 1000); */ + List restaurants = + await services.fetchRestaurantsByLocation(20.60912, 52.87728); + if (restaurants.isNotEmpty) { + for (Restaurant thisRestaurant in restaurants) { + final MarkerId markerId = MarkerId(thisRestaurant.name); + print(thisRestaurant.name); + final Marker marker = Marker( + markerId: markerId, + position: LatLng( + thisRestaurant.coordinates[0], thisRestaurant.coordinates[1]), + infoWindow: InfoWindow( + title: '${thisRestaurant.name}', + snippet: 'Kuchnia: ${thisRestaurant.type}')); + markers[markerId] = marker; + } + } + return markers; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: FutureBuilder>( + future: createMarkers(), + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + Map markers = snapshot.data; + List children; + if (snapshot.hasData) { + final CameraPosition _initialPosition = CameraPosition( + target: LatLng(20, 58), + zoom: 16, + ); + children = [ + GoogleMap( + mapType: MapType.normal, + initialCameraPosition: _initialPosition, + onMapCreated: (GoogleMapController controller) { + _controller.complete(controller); + }, + markers: Set.of(markers.values), + ), + ]; + } else if (snapshot.hasError) { + children = [Text('error')]; + } else { + children = [ + SizedBox( + child: CircularProgressIndicator(), + width: 60, + height: 60, + ), + Padding( + padding: EdgeInsets.only(top: 16), + child: Text('Awaiting result...'), + ) + ]; + } + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: children, + ), + ); + }, + ), + floatingActionButton: Padding( + padding: EdgeInsets.only(bottom: 20), + child: FloatingActionButton( + backgroundColor: Colors.grey[800], + onPressed: () { + Navigator.pop(context); + }, + child: Icon( + Icons.arrow_back_outlined, + color: Colors.orange, + ), + ), + ), + floatingActionButtonLocation: FloatingActionButtonLocation.startDocked, + ); + } +} diff --git a/lib/components/mapWithMarkers.dart b/lib/components/mapWithMarkers.dart deleted file mode 100644 index 1b3e2e0..0000000 --- a/lib/components/mapWithMarkers.dart +++ /dev/null @@ -1,10 +0,0 @@ -/* import 'package:flutter/material.dart'; -import '../services.dart'; */ -/* -class MapWithMarkers extends StatelessWidget { - @override - Widget build(BuildContext context) { - return - } -} - */ diff --git a/lib/components/restaurantMapView.dart b/lib/components/restaurantMapView.dart new file mode 100644 index 0000000..fd43498 --- /dev/null +++ b/lib/components/restaurantMapView.dart @@ -0,0 +1,62 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +class RestaurantMapView extends StatefulWidget { + final List coordinates; + final String name; + final String type; + + RestaurantMapView( + {@required this.coordinates, @required this.name, @required this.type}); + + @override + State createState() => RestaurantMapViewState(); +} + +class RestaurantMapViewState extends State { + Completer _controller = Completer(); + Map markers = {}; + + @override + Widget build(BuildContext context) { + final CameraPosition _initialPosition = CameraPosition( + target: LatLng(widget.coordinates[0], widget.coordinates[1]), + zoom: 17, + ); + final MarkerId markerId = MarkerId("restaurant-marker"); + final Marker marker = Marker( + markerId: markerId, + position: LatLng(widget.coordinates[0], widget.coordinates[1]), + infoWindow: InfoWindow( + title: '${widget.name}', snippet: 'Kuchnia: ${widget.type}')); + setState(() { + markers[MarkerId("restaurant-marker")] = marker; + }); + + return Scaffold( + body: GoogleMap( + mapType: MapType.normal, + initialCameraPosition: _initialPosition, + onMapCreated: (GoogleMapController controller) { + _controller.complete(controller); + }, + markers: Set.of(markers.values), + ), + floatingActionButton: Padding( + padding: EdgeInsets.only(bottom: 20), + child: FloatingActionButton( + backgroundColor: Colors.grey[800], + onPressed: () { + Navigator.pop(context); + }, + child: Icon( + Icons.arrow_back_outlined, + color: Colors.orange, + ), + ), + ), + floatingActionButtonLocation: FloatingActionButtonLocation.startDocked, + ); + } +} diff --git a/lib/components/restaurantView.dart b/lib/components/restaurantView.dart index 34e39fe..a61acb0 100644 --- a/lib/components/restaurantView.dart +++ b/lib/components/restaurantView.dart @@ -3,6 +3,7 @@ import '../services.dart'; import 'lineOfIcons.dart'; import 'dishList.dart'; import 'socialMedia.dart'; +import 'restaurantMapView.dart'; class RestaurantView extends StatelessWidget { final String id; @@ -78,7 +79,16 @@ class RestaurantView extends StatelessWidget { Icons.map, color: Colors.orange, ), - onPressed: () {}), + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + RestaurantMapView( + coordinates: + restaurant.coordinates, + name: restaurant.name, + type: restaurant.type, + )))), ) ], mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/components/searchBar.dart b/lib/components/searchBar.dart index bb602a7..f52d8bf 100644 --- a/lib/components/searchBar.dart +++ b/lib/components/searchBar.dart @@ -78,7 +78,6 @@ class MenuiSearchBarState extends State { behavior: HitTestBehavior.translucent, onTap: () { FocusScopeNode currentFocus = FocusScope.of(context); - print('12345'); if (!currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); } diff --git a/lib/services.dart b/lib/services.dart index 85afc3c..c62c336 100644 --- a/lib/services.dart +++ b/lib/services.dart @@ -1,9 +1,11 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/foundation.dart'; +import './settings.dart'; class MenuiServices { final String backendURL = 'https://api.menui.pl/'; + final MenuiSettings settings = new MenuiSettings(); Future> fetchAutocomplete(String text) async { final response = @@ -113,7 +115,7 @@ class MenuiServices { city: decoded['city'], adress: decoded['adress'], type: decoded['type'], - coordinates: decoded['coordinates'], + coordinates: decoded['location']['coordinates'], phone: decoded['phone'], imgUrl: decoded['imgUrl'], placesId: decoded['placesId'], @@ -140,11 +142,69 @@ class MenuiServices { lunchHours: decoded['lunchHours'], lunchMenu: lunchMenu, dishes: decoded['dishes']); - return result; } } + Future> fetchRestaurantsByLocation( + double lat, double lng) async { + final radius = await settings.getRadius(); + final response = await http + .get('${backendURL}search/location?lon=$lng&lat=$lat&radius=$radius'); + if (response.statusCode == 200 || response.statusCode == 304) { + final List decoded = jsonDecode(response.body); + List results = []; + for (var restaurant in decoded) { + final workingHours = restaurant['workingHours']; + final tags = restaurant['tags']; + final List responseLunchMenu = restaurant['lunchMenu']; + List lunchMenu = []; + if (responseLunchMenu != null) { + for (var lunchSet in responseLunchMenu) { + final MenuiLunchMenuSet thisSet = new MenuiLunchMenuSet( + lunchSet['lunchSetName'], + lunchSet['lunchSetPrice'], + lunchSet['lunchSetDishes']); + lunchMenu.add(thisSet); + } + } + final result = new Restaurant( + id: restaurant['_id'], + name: restaurant['name'], + city: restaurant['city'], + adress: restaurant['adress'], + type: restaurant['type'], + coordinates: restaurant['location']['coordinates'], + imgUrl: restaurant['imgUrl'], + placesId: restaurant['placesId'], + workingHours: new MenuiWorkingHours( + workingHours['pn'], + workingHours['wt'], + workingHours['sr'], + workingHours['cz'], + workingHours['pt'], + workingHours['sb'], + workingHours['nd']), + description: restaurant['description'], + tags: new MenuiTags( + tags['cardPayments'], + tags['petFriendly'], + tags['glutenFree'], + tags['vegan'], + tags['vegetarian'], + tags['alcohol'], + tags['delivery']), + lunchHours: restaurant['lunchHours'], + lunchMenu: lunchMenu, + dishes: restaurant['dishes']); + results.add(result); + } + return results; + } else { + return []; + } + } + Future> fetchSearchByString(String text) async { final response = await http.get('${backendURL}search?string=$text'); if (response.statusCode == 200 || response.statusCode == 304) { @@ -313,6 +373,15 @@ class Dish { this.vegetarian}); } +class MenuiMarker { + final List coordinates; + final String title; + final String type; + + MenuiMarker( + {@required this.coordinates, @required this.title, @required this.type}); +} + class MenuiPrices { MenuiPrice price1; MenuiPrice price2; diff --git a/pubspec.lock b/pubspec.lock index 5f3e1fc..f5acfc5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -76,6 +76,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.11" flutter_test: dependency: "direct dev" description: flutter @@ -107,6 +114,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.5" + google_maps_flutter: + dependency: "direct main" + description: + name: google_maps_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.6" + google_maps_flutter_platform_interface: + dependency: transitive + description: + name: google_maps_flutter_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" http: dependency: "direct main" description: @@ -266,6 +287,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0-nullsafety.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" string_scanner: dependency: transitive description: @@ -317,4 +345,4 @@ packages: version: "0.1.2" sdks: dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.22.0 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 0da43bd..400fa78 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,7 @@ dependencies: flutter: sdk: flutter shared_preferences: ^0.5.12 + google_maps_flutter: ^1.0.6 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons.