Update Place Tracker to use latest version of plugin (#59)

pull/61/head
Kenzie Schmoll 6 years ago committed by GitHub
parent 8fe2999ee8
commit a2419b3dcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,10 @@
analyzer:
errors:
# treat missing required parameters as a warning (not a hint)
missing_required_param: warning
# treat missing returns as a warning (not a hint)
missing_return: warning
linter:
rules:
- unawaited_futures

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '9.0' platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'

@ -1,10 +1,12 @@
#include "AppDelegate.h" #include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h" #include "GeneratedPluginRegistrant.h"
#import "GoogleMaps/GoogleMaps.h"
@implementation AppDelegate @implementation AppDelegate
- (BOOL)application:(UIApplication *)application - (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GMSServices provideAPIKey:@"YOUR KEY HERE"];
[GeneratedPluginRegistrant registerWithRegistry:self]; [GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch. // Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions]; return [super application:application didFinishLaunchingWithOptions:launchOptions];

@ -41,5 +41,7 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>io.flutter.embedded_views_preview</key>
<true/>
</dict> </dict>
</plist> </plist>

@ -25,6 +25,7 @@ class PlaceDetails extends StatefulWidget {
class PlaceDetailsState extends State<PlaceDetails> { class PlaceDetailsState extends State<PlaceDetails> {
Place _place; Place _place;
GoogleMapController _mapController; GoogleMapController _mapController;
final Set<Marker> _markers = {};
final TextEditingController _nameController = TextEditingController(); final TextEditingController _nameController = TextEditingController();
final TextEditingController _descriptionController = TextEditingController(); final TextEditingController _descriptionController = TextEditingController();
@ -39,7 +40,12 @@ class PlaceDetailsState extends State<PlaceDetails> {
void _onMapCreated(GoogleMapController controller) { void _onMapCreated(GoogleMapController controller) {
_mapController = controller; _mapController = controller;
_mapController.addMarker(MarkerOptions(position: _place.latLng)); setState(() {
_markers.add(Marker(
markerId: MarkerId(_place.latLng.toString()),
position: _place.latLng,
));
});
} }
Widget _detailsBody() { Widget _detailsBody() {
@ -74,6 +80,7 @@ class PlaceDetailsState extends State<PlaceDetails> {
center: _place.latLng, center: _place.latLng,
mapController: _mapController, mapController: _mapController,
onMapCreated: _onMapCreated, onMapCreated: _onMapCreated,
markers: _markers,
), ),
const _Reviews(), const _Reviews(),
], ],
@ -210,6 +217,7 @@ class _Map extends StatelessWidget {
@required this.center, @required this.center,
@required this.mapController, @required this.mapController,
@required this.onMapCreated, @required this.onMapCreated,
@required this.markers,
Key key, Key key,
}) : assert(center != null), }) : assert(center != null),
assert(onMapCreated != null), assert(onMapCreated != null),
@ -218,6 +226,7 @@ class _Map extends StatelessWidget {
final LatLng center; final LatLng center;
final GoogleMapController mapController; final GoogleMapController mapController;
final ArgumentCallback<GoogleMapController> onMapCreated; final ArgumentCallback<GoogleMapController> onMapCreated;
final Set<Marker> markers;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -229,16 +238,15 @@ class _Map extends StatelessWidget {
height: 240.0, height: 240.0,
child: GoogleMap( child: GoogleMap(
onMapCreated: onMapCreated, onMapCreated: onMapCreated,
options: GoogleMapOptions( initialCameraPosition: CameraPosition(
cameraPosition: CameraPosition( target: center,
target: center, zoom: 16.0,
zoom: 16.0,
),
zoomGesturesEnabled: false,
rotateGesturesEnabled: false,
tiltGesturesEnabled: false,
scrollGesturesEnabled: false,
), ),
markers: markers,
zoomGesturesEnabled: false,
rotateGesturesEnabled: false,
tiltGesturesEnabled: false,
scrollGesturesEnabled: false,
), ),
), ),
); );

@ -41,49 +41,55 @@ class PlaceMapState extends State<PlaceMap> {
return places.where((Place place) => place.category == category).toList(); return places.where((Place place) => place.category == category).toList();
} }
GoogleMapController mapController; Completer<GoogleMapController> mapController = Completer();
MapType _currentMapType = MapType.normal;
LatLng _lastMapPosition;
Map<Marker, Place> _markedPlaces = Map<Marker, Place>(); Map<Marker, Place> _markedPlaces = Map<Marker, Place>();
final Set<Marker> _markers = {};
Marker _pendingMarker; Marker _pendingMarker;
MapConfiguration _configuration; MapConfiguration _configuration;
void onMapCreated(GoogleMapController controller) async { void onMapCreated(GoogleMapController controller) async {
mapController = controller; mapController.complete(controller);
mapController.onInfoWindowTapped.add(_onInfoWindowTapped); _lastMapPosition = widget.center;
// Draw initial place markers on creation so that we have something // Draw initial place markers on creation so that we have something
// interesting to look at. // interesting to look at.
final Map<Marker, Place> places = await _markPlaces(); setState(() {
_zoomToFitPlaces( for (Place place in AppState.of(context).places) {
_markers.add(_createPlaceMarker(place));
}
});
// Zoom to fit the initially selected category.
await _zoomToFitPlaces(
_getPlacesForCategory( _getPlacesForCategory(
AppState.of(context).selectedCategory, AppState.of(context).selectedCategory,
places.values.toList(), _markedPlaces.values.toList(),
), ),
); );
} }
Future<Map<Marker, Place>> _markPlaces() async { Marker _createPlaceMarker(Place place) {
await Future.wait( final marker = Marker(
AppState.of(context).places.map((Place place) => _markPlace(place))); markerId: MarkerId(place.latLng.toString()),
return _markedPlaces; position: place.latLng,
} infoWindow: InfoWindow(
title: place.name,
Future<void> _markPlace(Place place) async { snippet: '${place.starRating} Star Rating',
final Marker marker = await mapController.addMarker( onTap: () => _pushPlaceDetailsScreen(place),
MarkerOptions(
position: place.latLng,
icon: _getPlaceMarkerIcon(place.category),
infoWindowText: InfoWindowText(
place.name,
'${place.starRating} Star Rating',
),
visible: place.category == AppState.of(context).selectedCategory,
), ),
icon: _getPlaceMarkerIcon(place.category),
visible: place.category == AppState.of(context).selectedCategory,
); );
_markedPlaces[marker] = place; _markedPlaces[marker] = place;
} return marker;
void _onInfoWindowTapped(Marker marker) {
_pushPlaceDetailsScreen(_markedPlaces[marker]);
} }
void _pushPlaceDetailsScreen(Place place) { void _pushPlaceDetailsScreen(Place place) {
@ -120,55 +126,64 @@ class PlaceMapState extends State<PlaceMap> {
AppState.updateWith(context, places: newPlaces); AppState.updateWith(context, places: newPlaces);
} }
Future<void> _updateExistingPlaceMarker({@required Place place}) async { void _updateExistingPlaceMarker({@required Place place}) {
Marker marker = _markedPlaces.keys Marker marker = _markedPlaces.keys
.singleWhere((Marker value) => _markedPlaces[value].id == place.id); .singleWhere((Marker value) => _markedPlaces[value].id == place.id);
// Set marker visibility to false to ensure the info window is hidden. Once setState(() {
// the plugin fully supports the Google Maps API, use hideInfoWindow() final updatedMarker = marker.copyWith(
// instead. infoWindowParam: InfoWindow(
await mapController.updateMarker( title: place.name,
marker, snippet:
MarkerOptions( place.starRating != 0 ? '${place.starRating} Star Rating' : null,
visible: false,
),
);
await mapController.updateMarker(
marker,
MarkerOptions(
infoWindowText: InfoWindowText(
place.name,
place.starRating != 0 ? '${place.starRating} Star Rating' : null,
), ),
visible: true, );
), _updateMarker(marker: marker, updatedMarker: updatedMarker, place: place);
); });
}
_markedPlaces[marker] = place; void _updateMarker({
@required Marker marker,
@required Marker updatedMarker,
@required Place place,
}) {
_markers.remove(marker);
_markedPlaces.remove(marker);
_markers.add(updatedMarker);
_markedPlaces[updatedMarker] = place;
} }
void _switchSelectedCategory(PlaceCategory category) { Future<void> _switchSelectedCategory(PlaceCategory category) async {
AppState.updateWith(context, selectedCategory: category); AppState.updateWith(context, selectedCategory: category);
_showPlacesForSelectedCategory(category); await _showPlacesForSelectedCategory(category);
} }
Future<void> _showPlacesForSelectedCategory(PlaceCategory category) async { Future<void> _showPlacesForSelectedCategory(PlaceCategory category) async {
await Future.wait( setState(() {
_markedPlaces.keys.map( for (Marker marker in List.of(_markedPlaces.keys)) {
(Marker marker) => mapController.updateMarker( final place = _markedPlaces[marker];
marker, final updatedMarker = marker.copyWith(
MarkerOptions( visibleParam: place.category == category,
visible: _markedPlaces[marker].category == category, );
),
),
),
);
_zoomToFitPlaces( _updateMarker(
_getPlacesForCategory(category, _markedPlaces.values.toList())); marker: marker,
updatedMarker: updatedMarker,
place: place,
);
}
});
await _zoomToFitPlaces(_getPlacesForCategory(
category,
_markedPlaces.values.toList(),
));
} }
void _zoomToFitPlaces(List<Place> places) { Future<void> _zoomToFitPlaces(List<Place> places) async {
GoogleMapController controller = await mapController.future;
// Default min/max values to latitude and longitude of center. // Default min/max values to latitude and longitude of center.
double minLat = widget.center.latitude; double minLat = widget.center.latitude;
double maxLat = widget.center.latitude; double maxLat = widget.center.latitude;
@ -182,7 +197,7 @@ class PlaceMapState extends State<PlaceMap> {
maxLong = max(maxLong, place.longitude); maxLong = max(maxLong, place.longitude);
} }
mapController.animateCamera( await controller.animateCamera(
CameraUpdate.newLatLngBounds( CameraUpdate.newLatLngBounds(
LatLngBounds( LatLngBounds(
southwest: LatLng(minLat, minLong), southwest: LatLng(minLat, minLong),
@ -194,40 +209,49 @@ class PlaceMapState extends State<PlaceMap> {
} }
void _onAddPlacePressed() async { void _onAddPlacePressed() async {
Marker newMarker = await mapController.addMarker( setState(() {
MarkerOptions( final newMarker = Marker(
position: LatLng( markerId: MarkerId(_lastMapPosition.toString()),
mapController.cameraPosition.target.latitude, position: _lastMapPosition,
mapController.cameraPosition.target.longitude, infoWindow: InfoWindow(title: 'New Place'),
),
draggable: true, draggable: true,
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen), icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen),
), );
); _markers.add(newMarker);
setState(() {
_pendingMarker = newMarker; _pendingMarker = newMarker;
}); });
} }
void _confirmAddPlace(BuildContext context) async { void _confirmAddPlace(BuildContext context) async {
if (_pendingMarker != null) { if (_pendingMarker != null) {
await mapController.updateMarker(
_pendingMarker,
MarkerOptions(
icon: _getPlaceMarkerIcon(AppState.of(context).selectedCategory),
infoWindowText: InfoWindowText('New Place', null),
draggable: false,
),
);
// Create a new Place and map it to the marker we just added. // Create a new Place and map it to the marker we just added.
final Place newPlace = Place( final Place newPlace = Place(
id: Uuid().v1(), id: Uuid().v1(),
latLng: _pendingMarker.options.position, latLng: _pendingMarker.position,
name: _pendingMarker.options.infoWindowText.title, name: _pendingMarker.infoWindow.title,
category: AppState.of(context).selectedCategory, category: AppState.of(context).selectedCategory,
); );
_markedPlaces[_pendingMarker] = newPlace;
setState(() {
final updatedMarker = _pendingMarker.copyWith(
iconParam: _getPlaceMarkerIcon(AppState.of(context).selectedCategory),
infoWindowParam: InfoWindow(
title: 'New Place',
snippet: null,
onTap: () => _pushPlaceDetailsScreen(newPlace),
),
draggableParam: false,
);
_updateMarker(
marker: _pendingMarker,
updatedMarker: updatedMarker,
place: newPlace,
);
_pendingMarker = null;
});
// Show a confirmation snackbar that has an action to edit the new place. // Show a confirmation snackbar that has an action to edit the new place.
Scaffold.of(context).showSnackBar( Scaffold.of(context).showSnackBar(
@ -257,29 +281,25 @@ class PlaceMapState extends State<PlaceMap> {
); );
AppState.updateWith(context, places: newPlaces); AppState.updateWith(context, places: newPlaces);
setState(() {
_pendingMarker = null;
});
} }
} }
void _cancelAddPlace() { void _cancelAddPlace() {
if (_pendingMarker != null) { if (_pendingMarker != null) {
mapController.removeMarker(_pendingMarker);
setState(() { setState(() {
_markers.remove(_pendingMarker);
_pendingMarker = null; _pendingMarker = null;
}); });
} }
} }
void _onToggleMapTypePressed() { void _onToggleMapTypePressed() {
final MapType nextType = MapType.values[ final MapType nextType =
(mapController.options.mapType.index + 1) % MapType.values.length]; MapType.values[(_currentMapType.index + 1) % MapType.values.length];
mapController.updateMapOptions( setState(() {
GoogleMapOptions(mapType: nextType), _currentMapType = nextType;
); });
} }
Future<void> _maybeUpdateMapConfiguration() async { Future<void> _maybeUpdateMapConfiguration() async {
@ -297,16 +317,15 @@ class PlaceMapState extends State<PlaceMap> {
newConfiguration.selectedCategory) { newConfiguration.selectedCategory) {
// If the configuration change is only a category change, just update // If the configuration change is only a category change, just update
// the marker visibilities. // the marker visibilities.
_showPlacesForSelectedCategory(newConfiguration.selectedCategory); await _showPlacesForSelectedCategory(newConfiguration.selectedCategory);
} else { } else {
// At this point, we know the places have been updated from the list // At this point, we know the places have been updated from the list
// view. We need to reconfigure the map to respect the updates. // view. We need to reconfigure the map to respect the updates.
await Future.wait( newConfiguration.places
newConfiguration.places .where((Place p) => !_configuration.places.contains(p))
.where((Place p) => !_configuration.places.contains(p)) .map((Place value) => _updateExistingPlaceMarker(place: value));
.map((Place value) => _updateExistingPlaceMarker(place: value)),
); await _zoomToFitPlaces(
_zoomToFitPlaces(
_getPlacesForCategory( _getPlacesForCategory(
newConfiguration.selectedCategory, newConfiguration.selectedCategory,
newConfiguration.places, newConfiguration.places,
@ -331,13 +350,13 @@ class PlaceMapState extends State<PlaceMap> {
children: <Widget>[ children: <Widget>[
GoogleMap( GoogleMap(
onMapCreated: onMapCreated, onMapCreated: onMapCreated,
options: GoogleMapOptions( initialCameraPosition: CameraPosition(
trackCameraPosition: true, target: widget.center,
cameraPosition: CameraPosition( zoom: 11.0,
target: widget.center,
zoom: 11.0,
),
), ),
mapType: _currentMapType,
markers: _markers,
onCameraMove: (position) => _lastMapPosition = position.target,
), ),
_CategoryButtonBar( _CategoryButtonBar(
selectedPlaceCategory: AppState.of(context).selectedCategory, selectedPlaceCategory: AppState.of(context).selectedCategory,

@ -12,7 +12,7 @@ dependencies:
cupertino_icons: ^0.1.2 cupertino_icons: ^0.1.2
google_maps_flutter: ^0.0.3 google_maps_flutter: ^0.4.0
uuid: 1.0.3 uuid: 1.0.3

Loading…
Cancel
Save