mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 22:09:06 +00:00
Updates travis config to include place_tracker and platform_view_swift (#42)
This commit is contained in:
@@ -11,7 +11,7 @@ addons:
|
|||||||
git:
|
git:
|
||||||
depth: 3
|
depth: 3
|
||||||
env:
|
env:
|
||||||
- FLUTTER_VERSION=beta
|
- FLUTTER_VERSION=stable
|
||||||
- FLUTTER_VERSION=dev
|
- FLUTTER_VERSION=dev
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ dev_dependencies:
|
|||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
dependency_overrides:
|
|
||||||
analyzer: 0.33.0
|
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
|
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class _AppModelScope<T> extends InheritedWidget {
|
|||||||
const _AppModelScope({
|
const _AppModelScope({
|
||||||
Key key,
|
Key key,
|
||||||
this.appModelState,
|
this.appModelState,
|
||||||
Widget child
|
Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
final _AppModelState<T> appModelState;
|
final _AppModelState<T> appModelState;
|
||||||
@@ -18,7 +18,7 @@ class AppModel<T> extends StatefulWidget {
|
|||||||
Key key,
|
Key key,
|
||||||
@required this.initialState,
|
@required this.initialState,
|
||||||
this.child,
|
this.child,
|
||||||
}) : assert(initialState != null),
|
}) : assert(initialState != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final T initialState;
|
final T initialState;
|
||||||
@@ -30,13 +30,15 @@ class AppModel<T> extends StatefulWidget {
|
|||||||
|
|
||||||
static T of<T>(BuildContext context) {
|
static T of<T>(BuildContext context) {
|
||||||
final Type appModelScopeType = _typeOf<_AppModelScope<T>>();
|
final Type appModelScopeType = _typeOf<_AppModelScope<T>>();
|
||||||
final _AppModelScope<T> scope = context.inheritFromWidgetOfExactType(appModelScopeType);
|
final _AppModelScope<T> scope =
|
||||||
|
context.inheritFromWidgetOfExactType(appModelScopeType);
|
||||||
return scope.appModelState.currentState;
|
return scope.appModelState.currentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update<T>(BuildContext context, T newState) {
|
static void update<T>(BuildContext context, T newState) {
|
||||||
final Type appModelScopeType = _typeOf<_AppModelScope<T>>();
|
final Type appModelScopeType = _typeOf<_AppModelScope<T>>();
|
||||||
final _AppModelScope<T> scope = context.inheritFromWidgetOfExactType(appModelScopeType);
|
final _AppModelScope<T> scope =
|
||||||
|
context.inheritFromWidgetOfExactType(appModelScopeType);
|
||||||
scope.appModelState.updateState(newState);
|
scope.appModelState.updateState(newState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ class Place {
|
|||||||
@required this.category,
|
@required this.category,
|
||||||
this.description,
|
this.description,
|
||||||
this.starRating = 0,
|
this.starRating = 0,
|
||||||
}) : assert(id != null),
|
}) : assert(id != null),
|
||||||
assert(latLng != null),
|
assert(latLng != null),
|
||||||
assert(name != null),
|
assert(name != null),
|
||||||
assert(category != null),
|
assert(category != null),
|
||||||
assert(starRating != null && starRating >= 0 && starRating <= 5);
|
assert(starRating != null && starRating >= 0 && starRating <= 5);
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
final LatLng latLng;
|
final LatLng latLng;
|
||||||
@@ -40,12 +40,12 @@ class Place {
|
|||||||
int starRating,
|
int starRating,
|
||||||
}) {
|
}) {
|
||||||
return Place(
|
return Place(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
latLng: latLng ?? this.latLng,
|
latLng: latLng ?? this.latLng,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
category: category ?? this.category,
|
category: category ?? this.category,
|
||||||
description: description ?? this.description,
|
description: description ?? this.description,
|
||||||
starRating: starRating ?? this.starRating,
|
starRating: starRating ?? this.starRating,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ class PlaceDetails extends StatefulWidget {
|
|||||||
@required this.place,
|
@required this.place,
|
||||||
@required this.onChanged,
|
@required this.onChanged,
|
||||||
Key key,
|
Key key,
|
||||||
}) : assert(place != null),
|
}) : assert(place != null),
|
||||||
assert(onChanged != null),
|
assert(onChanged != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final Place place;
|
final Place place;
|
||||||
final ValueChanged<Place> onChanged;
|
final ValueChanged<Place> onChanged;
|
||||||
@@ -23,7 +23,6 @@ class PlaceDetails extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PlaceDetailsState extends State<PlaceDetails> {
|
class PlaceDetailsState extends State<PlaceDetails> {
|
||||||
|
|
||||||
Place _place;
|
Place _place;
|
||||||
GoogleMapController _mapController;
|
GoogleMapController _mapController;
|
||||||
|
|
||||||
@@ -115,9 +114,9 @@ class _NameTextField extends StatelessWidget {
|
|||||||
@required this.controller,
|
@required this.controller,
|
||||||
@required this.onChanged,
|
@required this.onChanged,
|
||||||
Key key,
|
Key key,
|
||||||
}) : assert(controller != null),
|
}) : assert(controller != null),
|
||||||
assert(onChanged != null),
|
assert(onChanged != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final ValueChanged<String> onChanged;
|
final ValueChanged<String> onChanged;
|
||||||
@@ -147,9 +146,9 @@ class _DescriptionTextField extends StatelessWidget {
|
|||||||
@required this.controller,
|
@required this.controller,
|
||||||
@required this.onChanged,
|
@required this.onChanged,
|
||||||
Key key,
|
Key key,
|
||||||
}) : assert(controller != null),
|
}) : assert(controller != null),
|
||||||
assert(onChanged != null),
|
assert(onChanged != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final ValueChanged<String> onChanged;
|
final ValueChanged<String> onChanged;
|
||||||
@@ -180,9 +179,9 @@ class _StarBar extends StatelessWidget {
|
|||||||
@required this.rating,
|
@required this.rating,
|
||||||
@required this.onChanged,
|
@required this.onChanged,
|
||||||
Key key,
|
Key key,
|
||||||
}) : assert(rating != null && rating >= 0 && rating <= maxStars),
|
}) : assert(rating != null && rating >= 0 && rating <= maxStars),
|
||||||
assert(onChanged != null),
|
assert(onChanged != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
static const int maxStars = 5;
|
static const int maxStars = 5;
|
||||||
final int rating;
|
final int rating;
|
||||||
@@ -212,9 +211,9 @@ class _Map extends StatelessWidget {
|
|||||||
@required this.mapController,
|
@required this.mapController,
|
||||||
@required this.onMapCreated,
|
@required this.onMapCreated,
|
||||||
Key key,
|
Key key,
|
||||||
}) : assert(center != null),
|
}) : assert(center != null),
|
||||||
assert(onMapCreated != null),
|
assert(onMapCreated != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final LatLng center;
|
final LatLng center;
|
||||||
final GoogleMapController mapController;
|
final GoogleMapController mapController;
|
||||||
@@ -326,7 +325,9 @@ class _Reviews extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: StubData.reviewStrings.map((reviewText) => _buildSingleReview(reviewText)).toList(),
|
children: StubData.reviewStrings
|
||||||
|
.map((reviewText) => _buildSingleReview(reviewText))
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'place_details.dart';
|
|||||||
import 'place_tracker_app.dart';
|
import 'place_tracker_app.dart';
|
||||||
|
|
||||||
class PlaceList extends StatefulWidget {
|
class PlaceList extends StatefulWidget {
|
||||||
const PlaceList({ Key key }) : super(key: key);
|
const PlaceList({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
PlaceListState createState() => PlaceListState();
|
PlaceListState createState() => PlaceListState();
|
||||||
@@ -22,7 +22,8 @@ class PlaceListState extends State<PlaceList> {
|
|||||||
void _onPlaceChanged(Place value) {
|
void _onPlaceChanged(Place value) {
|
||||||
// Replace the place with the modified version.
|
// Replace the place with the modified version.
|
||||||
final List<Place> newPlaces = List.from(AppState.of(context).places);
|
final List<Place> newPlaces = List.from(AppState.of(context).places);
|
||||||
final int index = newPlaces.indexWhere((Place place) => place.id == value.id);
|
final int index =
|
||||||
|
newPlaces.indexWhere((Place place) => place.id == value.id);
|
||||||
newPlaces[index] = value;
|
newPlaces[index] = value;
|
||||||
|
|
||||||
AppState.updateWith(context, places: newPlaces);
|
AppState.updateWith(context, places: newPlaces);
|
||||||
@@ -41,16 +42,18 @@ class PlaceListState extends State<PlaceList> {
|
|||||||
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 8.0),
|
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 8.0),
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: AppState.of(context).places
|
children: AppState.of(context)
|
||||||
.where((Place place) => place.category == AppState.of(context).selectedCategory)
|
.places
|
||||||
.map((Place place) => _PlaceListTile(
|
.where((Place place) =>
|
||||||
place: place,
|
place.category == AppState.of(context).selectedCategory)
|
||||||
onPlaceChanged: (Place value) => _onPlaceChanged(value),
|
.map((Place place) => _PlaceListTile(
|
||||||
)
|
place: place,
|
||||||
).toList(),
|
onPlaceChanged: (Place value) => _onPlaceChanged(value),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,9 +63,9 @@ class _PlaceListTile extends StatelessWidget {
|
|||||||
Key key,
|
Key key,
|
||||||
@required this.place,
|
@required this.place,
|
||||||
@required this.onPlaceChanged,
|
@required this.onPlaceChanged,
|
||||||
}) : assert(place != null),
|
}) : assert(place != null),
|
||||||
assert(onPlaceChanged != null),
|
assert(onPlaceChanged != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final Place place;
|
final Place place;
|
||||||
final ValueChanged<Place> onPlaceChanged;
|
final ValueChanged<Place> onPlaceChanged;
|
||||||
@@ -71,14 +74,14 @@ class _PlaceListTile extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => Navigator.push(
|
onTap: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (context) {
|
MaterialPageRoute(builder: (context) {
|
||||||
return PlaceDetails(
|
return PlaceDetails(
|
||||||
place: place,
|
place: place,
|
||||||
onChanged: (Place value) => onPlaceChanged(value),
|
onChanged: (Place value) => onPlaceChanged(value),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.only(top: 16.0),
|
padding: EdgeInsets.only(top: 16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -95,9 +98,12 @@ class _PlaceListTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: List.generate(5, (int index) {
|
children: List.generate(5, (int index) {
|
||||||
return Icon(Icons.star,
|
return Icon(
|
||||||
|
Icons.star,
|
||||||
size: 28.0,
|
size: 28.0,
|
||||||
color: place.starRating > index ? Colors.amber : Colors.grey[400],
|
color: place.starRating > index
|
||||||
|
? Colors.amber
|
||||||
|
: Colors.grey[400],
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
@@ -124,9 +130,9 @@ class _ListCategoryButtonBar extends StatelessWidget {
|
|||||||
Key key,
|
Key key,
|
||||||
@required this.selectedCategory,
|
@required this.selectedCategory,
|
||||||
@required this.onCategoryChanged,
|
@required this.onCategoryChanged,
|
||||||
}) : assert(selectedCategory != null),
|
}) : assert(selectedCategory != null),
|
||||||
assert(onCategoryChanged != null),
|
assert(onCategoryChanged != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final PlaceCategory selectedCategory;
|
final PlaceCategory selectedCategory;
|
||||||
final ValueChanged<PlaceCategory> onCategoryChanged;
|
final ValueChanged<PlaceCategory> onCategoryChanged;
|
||||||
@@ -140,11 +146,13 @@ class _ListCategoryButtonBar extends StatelessWidget {
|
|||||||
category: PlaceCategory.favorite,
|
category: PlaceCategory.favorite,
|
||||||
selected: selectedCategory == PlaceCategory.favorite,
|
selected: selectedCategory == PlaceCategory.favorite,
|
||||||
onCategoryChanged: onCategoryChanged,
|
onCategoryChanged: onCategoryChanged,
|
||||||
),_CategoryButton(
|
),
|
||||||
|
_CategoryButton(
|
||||||
category: PlaceCategory.visited,
|
category: PlaceCategory.visited,
|
||||||
selected: selectedCategory == PlaceCategory.visited,
|
selected: selectedCategory == PlaceCategory.visited,
|
||||||
onCategoryChanged: onCategoryChanged,
|
onCategoryChanged: onCategoryChanged,
|
||||||
),_CategoryButton(
|
),
|
||||||
|
_CategoryButton(
|
||||||
category: PlaceCategory.wantToGo,
|
category: PlaceCategory.wantToGo,
|
||||||
selected: selectedCategory == PlaceCategory.wantToGo,
|
selected: selectedCategory == PlaceCategory.wantToGo,
|
||||||
onCategoryChanged: onCategoryChanged,
|
onCategoryChanged: onCategoryChanged,
|
||||||
@@ -160,9 +168,9 @@ class _CategoryButton extends StatelessWidget {
|
|||||||
@required this.category,
|
@required this.category,
|
||||||
@required this.selected,
|
@required this.selected,
|
||||||
@required this.onCategoryChanged,
|
@required this.onCategoryChanged,
|
||||||
}) : assert(category != null),
|
}) : assert(category != null),
|
||||||
assert(selected != null),
|
assert(selected != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final PlaceCategory category;
|
final PlaceCategory category;
|
||||||
final bool selected;
|
final bool selected;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ class PlaceMap extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PlaceMapState extends State<PlaceMap> {
|
class PlaceMapState extends State<PlaceMap> {
|
||||||
|
|
||||||
static BitmapDescriptor _getPlaceMarkerIcon(PlaceCategory category) {
|
static BitmapDescriptor _getPlaceMarkerIcon(PlaceCategory category) {
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case PlaceCategory.favorite:
|
case PlaceCategory.favorite:
|
||||||
@@ -36,7 +35,8 @@ class PlaceMapState extends State<PlaceMap> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<Place> _getPlacesForCategory(PlaceCategory category, List<Place> places) {
|
static List<Place> _getPlacesForCategory(
|
||||||
|
PlaceCategory category, List<Place> places) {
|
||||||
return places.where((Place place) => place.category == category).toList();
|
return places.where((Place place) => place.category == category).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +61,8 @@ class PlaceMapState extends State<PlaceMap> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<Marker, Place>> _markPlaces() async {
|
Future<Map<Marker, Place>> _markPlaces() async {
|
||||||
await Future.wait(AppState.of(context).places.map((Place place) => _markPlace(place)));
|
await Future.wait(
|
||||||
|
AppState.of(context).places.map((Place place) => _markPlace(place)));
|
||||||
return _markedPlaces;
|
return _markedPlaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +102,8 @@ class PlaceMapState extends State<PlaceMap> {
|
|||||||
void _onPlaceChanged(Place value) {
|
void _onPlaceChanged(Place value) {
|
||||||
// Replace the place with the modified version.
|
// Replace the place with the modified version.
|
||||||
final List<Place> newPlaces = List.from(AppState.of(context).places);
|
final List<Place> newPlaces = List.from(AppState.of(context).places);
|
||||||
final int index = newPlaces.indexWhere((Place place) => place.id == value.id);
|
final int index =
|
||||||
|
newPlaces.indexWhere((Place place) => place.id == value.id);
|
||||||
newPlaces[index] = value;
|
newPlaces[index] = value;
|
||||||
|
|
||||||
_updateExistingPlaceMarker(place: value);
|
_updateExistingPlaceMarker(place: value);
|
||||||
@@ -117,10 +119,9 @@ class PlaceMapState extends State<PlaceMap> {
|
|||||||
AppState.updateWith(context, places: newPlaces);
|
AppState.updateWith(context, places: newPlaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateExistingPlaceMarker({@required Place place}) async {
|
Future<void> _updateExistingPlaceMarker({@required Place place}) async {
|
||||||
Marker marker =
|
Marker marker = _markedPlaces.keys
|
||||||
_markedPlaces.keys.singleWhere(
|
.singleWhere((Marker value) => _markedPlaces[value].id == place.id);
|
||||||
(Marker value) => _markedPlaces[value].id == place.id);
|
|
||||||
|
|
||||||
// Set marker visibility to false to ensure the info window is hidden. Once
|
// Set marker visibility to false to ensure the info window is hidden. Once
|
||||||
// the plugin fully supports the Google Maps API, use hideInfoWindow()
|
// the plugin fully supports the Google Maps API, use hideInfoWindow()
|
||||||
@@ -136,9 +137,7 @@ class PlaceMapState extends State<PlaceMap> {
|
|||||||
MarkerOptions(
|
MarkerOptions(
|
||||||
infoWindowText: InfoWindowText(
|
infoWindowText: InfoWindowText(
|
||||||
place.name,
|
place.name,
|
||||||
place.starRating != 0
|
place.starRating != 0 ? '${place.starRating} Star Rating' : null,
|
||||||
? '${place.starRating} Star Rating'
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
visible: true,
|
visible: true,
|
||||||
),
|
),
|
||||||
@@ -152,16 +151,20 @@ class PlaceMapState extends State<PlaceMap> {
|
|||||||
_showPlacesForSelectedCategory(category);
|
_showPlacesForSelectedCategory(category);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showPlacesForSelectedCategory(PlaceCategory category) async {
|
Future<void> _showPlacesForSelectedCategory(PlaceCategory category) async {
|
||||||
await _markedPlaces.forEach((Marker marker, Place place) {
|
await Future.wait(
|
||||||
mapController.updateMarker(
|
_markedPlaces.keys.map(
|
||||||
marker,
|
(Marker marker) => mapController.updateMarker(
|
||||||
MarkerOptions(
|
marker,
|
||||||
visible: place.category == category,
|
MarkerOptions(
|
||||||
),
|
visible: _markedPlaces[marker].category == category,
|
||||||
);
|
),
|
||||||
});
|
),
|
||||||
_zoomToFitPlaces(_getPlacesForCategory(category, _markedPlaces.values.toList()));
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
_zoomToFitPlaces(
|
||||||
|
_getPlacesForCategory(category, _markedPlaces.values.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _zoomToFitPlaces(List<Place> places) {
|
void _zoomToFitPlaces(List<Place> places) {
|
||||||
@@ -229,10 +232,8 @@ class PlaceMapState extends State<PlaceMap> {
|
|||||||
Scaffold.of(context).showSnackBar(
|
Scaffold.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
duration: Duration(seconds: 3),
|
duration: Duration(seconds: 3),
|
||||||
content: const Text(
|
content: const Text('New place added.',
|
||||||
'New place added.',
|
style: const TextStyle(fontSize: 16.0)),
|
||||||
style: const TextStyle(fontSize: 16.0)
|
|
||||||
),
|
|
||||||
action: SnackBarAction(
|
action: SnackBarAction(
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@@ -272,36 +273,38 @@ class PlaceMapState extends State<PlaceMap> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onToggleMapTypePressed() {
|
void _onToggleMapTypePressed() {
|
||||||
final MapType nextType =
|
final MapType nextType = MapType.values[
|
||||||
MapType.values[(mapController.options.mapType.index + 1) % MapType.values.length];
|
(mapController.options.mapType.index + 1) % MapType.values.length];
|
||||||
|
|
||||||
mapController.updateMapOptions(
|
mapController.updateMapOptions(
|
||||||
GoogleMapOptions(mapType: nextType),
|
GoogleMapOptions(mapType: nextType),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _maybeUpdateMapConfiguration() async {
|
Future<void> _maybeUpdateMapConfiguration() async {
|
||||||
_configuration ??= MapConfiguration.of(AppState.of(context));
|
_configuration ??= MapConfiguration.of(AppState.of(context));
|
||||||
final MapConfiguration newConfiguration = MapConfiguration.of(AppState.of(context));
|
final MapConfiguration newConfiguration =
|
||||||
|
MapConfiguration.of(AppState.of(context));
|
||||||
|
|
||||||
// Since we manually update [_configuration] when place or selectedCategory
|
// Since we manually update [_configuration] when place or selectedCategory
|
||||||
// changes come from the [place_map], we should only enter this if statement
|
// changes come from the [place_map], we should only enter this if statement
|
||||||
// when returning to the [place_map] after changes have been made from
|
// when returning to the [place_map] after changes have been made from
|
||||||
// [place_list].
|
// [place_list].
|
||||||
if (_configuration != newConfiguration && mapController != null) {
|
if (_configuration != newConfiguration && mapController != null) {
|
||||||
if (_configuration.places == newConfiguration.places
|
if (_configuration.places == newConfiguration.places &&
|
||||||
&& _configuration.selectedCategory != newConfiguration.selectedCategory) {
|
_configuration.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);
|
_showPlacesForSelectedCategory(newConfiguration.selectedCategory);
|
||||||
} else {
|
} else {
|
||||||
// At this point, we know the places have been updated from the list view.
|
// At this point, we know the places have been updated from the list
|
||||||
// We need to reconfigure the map to respect the updates.
|
// view. We need to reconfigure the map to respect the updates.
|
||||||
await newConfiguration.places.forEach((Place value) {
|
await Future.wait(
|
||||||
if (!_configuration.places.contains(value)) {
|
newConfiguration.places
|
||||||
_updateExistingPlaceMarker(place: value);
|
.where((Place p) => !_configuration.places.contains(p))
|
||||||
}
|
.map((Place value) => _updateExistingPlaceMarker(place: value)),
|
||||||
});
|
);
|
||||||
_zoomToFitPlaces(
|
_zoomToFitPlaces(
|
||||||
_getPlacesForCategory(
|
_getPlacesForCategory(
|
||||||
newConfiguration.selectedCategory,
|
newConfiguration.selectedCategory,
|
||||||
@@ -363,10 +366,10 @@ class _CategoryButtonBar extends StatelessWidget {
|
|||||||
@required this.selectedPlaceCategory,
|
@required this.selectedPlaceCategory,
|
||||||
@required this.visible,
|
@required this.visible,
|
||||||
@required this.onChanged,
|
@required this.onChanged,
|
||||||
}) : assert(selectedPlaceCategory != null),
|
}) : assert(selectedPlaceCategory != null),
|
||||||
assert(visible != null),
|
assert(visible != null),
|
||||||
assert(onChanged != null),
|
assert(onChanged != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final PlaceCategory selectedPlaceCategory;
|
final PlaceCategory selectedPlaceCategory;
|
||||||
final bool visible;
|
final bool visible;
|
||||||
@@ -384,8 +387,8 @@ class _CategoryButtonBar extends StatelessWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
RaisedButton(
|
RaisedButton(
|
||||||
color: selectedPlaceCategory == PlaceCategory.favorite
|
color: selectedPlaceCategory == PlaceCategory.favorite
|
||||||
? Colors.green[700]
|
? Colors.green[700]
|
||||||
: Colors.lightGreen,
|
: Colors.lightGreen,
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Favorites',
|
'Favorites',
|
||||||
style: TextStyle(color: Colors.white, fontSize: 14.0),
|
style: TextStyle(color: Colors.white, fontSize: 14.0),
|
||||||
@@ -394,8 +397,8 @@ class _CategoryButtonBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
RaisedButton(
|
RaisedButton(
|
||||||
color: selectedPlaceCategory == PlaceCategory.visited
|
color: selectedPlaceCategory == PlaceCategory.visited
|
||||||
? Colors.green[700]
|
? Colors.green[700]
|
||||||
: Colors.lightGreen,
|
: Colors.lightGreen,
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Visited',
|
'Visited',
|
||||||
style: TextStyle(color: Colors.white, fontSize: 14.0),
|
style: TextStyle(color: Colors.white, fontSize: 14.0),
|
||||||
@@ -404,8 +407,8 @@ class _CategoryButtonBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
RaisedButton(
|
RaisedButton(
|
||||||
color: selectedPlaceCategory == PlaceCategory.wantToGo
|
color: selectedPlaceCategory == PlaceCategory.wantToGo
|
||||||
? Colors.green[700]
|
? Colors.green[700]
|
||||||
: Colors.lightGreen,
|
: Colors.lightGreen,
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Want To Go',
|
'Want To Go',
|
||||||
style: TextStyle(color: Colors.white, fontSize: 14.0),
|
style: TextStyle(color: Colors.white, fontSize: 14.0),
|
||||||
@@ -419,16 +422,16 @@ class _CategoryButtonBar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AddPlaceButtonBar extends StatelessWidget {
|
class _AddPlaceButtonBar extends StatelessWidget {
|
||||||
const _AddPlaceButtonBar({
|
const _AddPlaceButtonBar({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.visible,
|
@required this.visible,
|
||||||
@required this.onSavePressed,
|
@required this.onSavePressed,
|
||||||
@required this.onCancelPressed,
|
@required this.onCancelPressed,
|
||||||
}) : assert(visible != null),
|
}) : assert(visible != null),
|
||||||
assert(onSavePressed != null),
|
assert(onSavePressed != null),
|
||||||
assert(onCancelPressed != null),
|
assert(onCancelPressed != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final bool visible;
|
final bool visible;
|
||||||
final VoidCallback onSavePressed;
|
final VoidCallback onSavePressed;
|
||||||
@@ -473,7 +476,7 @@ class _MapFabs extends StatelessWidget {
|
|||||||
@required this.visible,
|
@required this.visible,
|
||||||
@required this.onAddPlacePressed,
|
@required this.onAddPlacePressed,
|
||||||
@required this.onToggleMapTypePressed,
|
@required this.onToggleMapTypePressed,
|
||||||
}) : assert(visible != null),
|
}) : assert(visible != null),
|
||||||
assert(onAddPlacePressed != null),
|
assert(onAddPlacePressed != null),
|
||||||
assert(onToggleMapTypePressed != null),
|
assert(onToggleMapTypePressed != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
@@ -518,21 +521,28 @@ class MapConfiguration {
|
|||||||
const MapConfiguration({
|
const MapConfiguration({
|
||||||
@required this.places,
|
@required this.places,
|
||||||
@required this.selectedCategory,
|
@required this.selectedCategory,
|
||||||
}) : assert(places != null),
|
}) : assert(places != null),
|
||||||
assert(selectedCategory != null);
|
assert(selectedCategory != null);
|
||||||
|
|
||||||
final List<Place> places;
|
final List<Place> places;
|
||||||
final PlaceCategory selectedCategory;
|
final PlaceCategory selectedCategory;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => places.hashCode ^ selectedCategory.hashCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
if (identical(this, other))
|
if (identical(this, other)) {
|
||||||
return true;
|
return true;
|
||||||
if (other.runtimeType != runtimeType)
|
}
|
||||||
|
|
||||||
|
if (other.runtimeType != runtimeType) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
final MapConfiguration otherConfiguration = other;
|
final MapConfiguration otherConfiguration = other;
|
||||||
return otherConfiguration.places == places
|
return otherConfiguration.places == places &&
|
||||||
&& otherConfiguration.selectedCategory == selectedCategory;
|
otherConfiguration.selectedCategory == selectedCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MapConfiguration of(AppState appState) {
|
static MapConfiguration of(AppState appState) {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class _PlaceTrackerAppState extends State<PlaceTrackerApp> {
|
|||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
builder: (BuildContext context, Widget child) {
|
builder: (BuildContext context, Widget child) {
|
||||||
return AppModel<AppState>(
|
return AppModel<AppState>(
|
||||||
initialState: AppState(),
|
initialState: AppState(),
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
home: _PlaceTrackerHomePage(),
|
home: _PlaceTrackerHomePage(),
|
||||||
@@ -35,7 +35,7 @@ class _PlaceTrackerAppState extends State<PlaceTrackerApp> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PlaceTrackerHomePage extends StatelessWidget {
|
class _PlaceTrackerHomePage extends StatelessWidget {
|
||||||
const _PlaceTrackerHomePage({ Key key }) : super(key: key);
|
const _PlaceTrackerHomePage({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -57,17 +57,18 @@ class _PlaceTrackerHomePage extends StatelessWidget {
|
|||||||
padding: EdgeInsets.fromLTRB(0.0, 0.0, 16.0, 0.0),
|
padding: EdgeInsets.fromLTRB(0.0, 0.0, 16.0, 0.0),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
AppState.of(context).viewType == PlaceTrackerViewType.map
|
AppState.of(context).viewType == PlaceTrackerViewType.map
|
||||||
? Icons.list
|
? Icons.list
|
||||||
: Icons.map,
|
: Icons.map,
|
||||||
size: 32.0
|
size: 32.0,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AppState.updateWith(
|
AppState.updateWith(
|
||||||
context,
|
context,
|
||||||
viewType: AppState.of(context).viewType == PlaceTrackerViewType.map
|
viewType:
|
||||||
? PlaceTrackerViewType.list
|
AppState.of(context).viewType == PlaceTrackerViewType.map
|
||||||
: PlaceTrackerViewType.map,
|
? PlaceTrackerViewType.list
|
||||||
|
: PlaceTrackerViewType.map,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -75,7 +76,8 @@ class _PlaceTrackerHomePage extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: IndexedStack(
|
body: IndexedStack(
|
||||||
index: AppState.of(context).viewType == PlaceTrackerViewType.map ? 0 : 1,
|
index:
|
||||||
|
AppState.of(context).viewType == PlaceTrackerViewType.map ? 0 : 1,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
PlaceMap(center: const LatLng(45.521563, -122.677433)),
|
PlaceMap(center: const LatLng(45.521563, -122.677433)),
|
||||||
PlaceList(),
|
PlaceList(),
|
||||||
@@ -90,7 +92,7 @@ class AppState {
|
|||||||
this.places = StubData.places,
|
this.places = StubData.places,
|
||||||
this.selectedCategory = PlaceCategory.favorite,
|
this.selectedCategory = PlaceCategory.favorite,
|
||||||
this.viewType = PlaceTrackerViewType.map,
|
this.viewType = PlaceTrackerViewType.map,
|
||||||
}) : assert(places != null),
|
}) : assert(places != null),
|
||||||
assert(selectedCategory != null);
|
assert(selectedCategory != null);
|
||||||
|
|
||||||
final List<Place> places;
|
final List<Place> places;
|
||||||
@@ -116,29 +118,29 @@ class AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void updateWith(
|
static void updateWith(
|
||||||
BuildContext context,
|
BuildContext context, {
|
||||||
{List<Place> places,
|
List<Place> places,
|
||||||
PlaceCategory selectedCategory,
|
PlaceCategory selectedCategory,
|
||||||
PlaceTrackerViewType viewType,
|
PlaceTrackerViewType viewType,
|
||||||
}) {
|
}) {
|
||||||
update(
|
update(
|
||||||
context,
|
context,
|
||||||
AppState.of(context).copyWith(
|
AppState.of(context).copyWith(
|
||||||
places: places, selectedCategory: selectedCategory, viewType: viewType,
|
places: places,
|
||||||
|
selectedCategory: selectedCategory,
|
||||||
|
viewType: viewType,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
if (identical(this, other))
|
if (identical(this, other)) return true;
|
||||||
return true;
|
if (other.runtimeType != runtimeType) return false;
|
||||||
if (other.runtimeType != runtimeType)
|
|
||||||
return false;
|
|
||||||
final AppState otherAppState = other;
|
final AppState otherAppState = other;
|
||||||
return otherAppState.places == places
|
return otherAppState.places == places &&
|
||||||
&& otherAppState.selectedCategory == selectedCategory
|
otherAppState.selectedCategory == selectedCategory &&
|
||||||
&& otherAppState.viewType == viewType;
|
otherAppState.viewType == viewType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ class StubData {
|
|||||||
id: '2',
|
id: '2',
|
||||||
latLng: LatLng(45.516887, -122.675417),
|
latLng: LatLng(45.516887, -122.675417),
|
||||||
name: 'Luc Lac Vietnamese Kitchen',
|
name: 'Luc Lac Vietnamese Kitchen',
|
||||||
description: 'Popular counter-serve offering pho, banh mi & other Vietnamese favorites in a stylish setting.',
|
description:
|
||||||
|
'Popular counter-serve offering pho, banh mi & other Vietnamese favorites in a stylish setting.',
|
||||||
category: PlaceCategory.favorite,
|
category: PlaceCategory.favorite,
|
||||||
starRating: 5,
|
starRating: 5,
|
||||||
),
|
),
|
||||||
@@ -26,7 +27,7 @@ class StubData {
|
|||||||
latLng: LatLng(45.528952, -122.698344),
|
latLng: LatLng(45.528952, -122.698344),
|
||||||
name: 'Salt & Straw',
|
name: 'Salt & Straw',
|
||||||
description:
|
description:
|
||||||
'Quirky flavors & handmade waffle cones draw crowds to this artisinal ice cream maker\'s 3 parlors.',
|
'Quirky flavors & handmade waffle cones draw crowds to this artisinal ice cream maker\'s 3 parlors.',
|
||||||
category: PlaceCategory.favorite,
|
category: PlaceCategory.favorite,
|
||||||
starRating: 5,
|
starRating: 5,
|
||||||
),
|
),
|
||||||
@@ -53,7 +54,7 @@ class StubData {
|
|||||||
latLng: LatLng(45.487137, -122.799940),
|
latLng: LatLng(45.487137, -122.799940),
|
||||||
name: 'Buffalo Wild Wings',
|
name: 'Buffalo Wild Wings',
|
||||||
description:
|
description:
|
||||||
'Lively sports-bar chain dishing up wings & other American pub grub amid lots of large-screen TVs.',
|
'Lively sports-bar chain dishing up wings & other American pub grub amid lots of large-screen TVs.',
|
||||||
category: PlaceCategory.visited,
|
category: PlaceCategory.visited,
|
||||||
starRating: 5,
|
starRating: 5,
|
||||||
),
|
),
|
||||||
@@ -62,7 +63,7 @@ class StubData {
|
|||||||
latLng: LatLng(45.416986, -122.743171),
|
latLng: LatLng(45.416986, -122.743171),
|
||||||
name: 'Chevys',
|
name: 'Chevys',
|
||||||
description:
|
description:
|
||||||
'Lively, informal Mexican chain with a colorful, family-friendly setting plus tequilas & margaritas.',
|
'Lively, informal Mexican chain with a colorful, family-friendly setting plus tequilas & margaritas.',
|
||||||
category: PlaceCategory.visited,
|
category: PlaceCategory.visited,
|
||||||
starRating: 4,
|
starRating: 4,
|
||||||
),
|
),
|
||||||
@@ -71,7 +72,7 @@ class StubData {
|
|||||||
latLng: LatLng(45.430489, -122.831802),
|
latLng: LatLng(45.430489, -122.831802),
|
||||||
name: 'Cinetopia',
|
name: 'Cinetopia',
|
||||||
description:
|
description:
|
||||||
'Moviegoers can take food from the on-site eatery to their seats, with table service in 21+ theaters.',
|
'Moviegoers can take food from the on-site eatery to their seats, with table service in 21+ theaters.',
|
||||||
category: PlaceCategory.visited,
|
category: PlaceCategory.visited,
|
||||||
starRating: 4,
|
starRating: 4,
|
||||||
),
|
),
|
||||||
@@ -107,7 +108,7 @@ class StubData {
|
|||||||
latLng: LatLng(45.420226, -122.740347),
|
latLng: LatLng(45.420226, -122.740347),
|
||||||
name: 'Oswego Grill',
|
name: 'Oswego Grill',
|
||||||
description:
|
description:
|
||||||
'Wood-grilled steakhouse favorites served in a casual, romantic restaurant with a popular happy hour.',
|
'Wood-grilled steakhouse favorites served in a casual, romantic restaurant with a popular happy hour.',
|
||||||
category: PlaceCategory.wantToGo,
|
category: PlaceCategory.wantToGo,
|
||||||
starRating: 4,
|
starRating: 4,
|
||||||
),
|
),
|
||||||
@@ -116,7 +117,7 @@ class StubData {
|
|||||||
latLng: LatLng(45.541202, -122.676432),
|
latLng: LatLng(45.541202, -122.676432),
|
||||||
name: 'The Widmer Brothers Brewery',
|
name: 'The Widmer Brothers Brewery',
|
||||||
description:
|
description:
|
||||||
'Popular, enduring gastropub serving craft beers, sandwiches & eclectic entrees in a laid-back space.',
|
'Popular, enduring gastropub serving craft beers, sandwiches & eclectic entrees in a laid-back space.',
|
||||||
category: PlaceCategory.wantToGo,
|
category: PlaceCategory.wantToGo,
|
||||||
starRating: 4,
|
starRating: 4,
|
||||||
),
|
),
|
||||||
@@ -133,7 +134,8 @@ class StubData {
|
|||||||
id: '15',
|
id: '15',
|
||||||
latLng: LatLng(45.485612, -122.784733),
|
latLng: LatLng(45.485612, -122.784733),
|
||||||
name: 'Uwajimaya Beaverton',
|
name: 'Uwajimaya Beaverton',
|
||||||
description: 'Huge Asian grocery outpost stocking meats, produce & prepared foods plus gifts & home goods.',
|
description:
|
||||||
|
'Huge Asian grocery outpost stocking meats, produce & prepared foods plus gifts & home goods.',
|
||||||
category: PlaceCategory.wantToGo,
|
category: PlaceCategory.wantToGo,
|
||||||
starRating: 5,
|
starRating: 5,
|
||||||
),
|
),
|
||||||
|
|||||||
11
place_tracker/test/widget_test.dart
Normal file
11
place_tracker/test/widget_test.dart
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// This is a basic Flutter widget test.
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
|
||||||
|
// provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
|
||||||
|
// find child widgets in the widget tree, read text, and verify that the values of widget properties
|
||||||
|
// are correct.
|
||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('This test always passes', (WidgetTester tester) async {});
|
||||||
|
}
|
||||||
@@ -66,7 +66,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
new Text(
|
new Text(
|
||||||
'Button tapped $_counter time${ _counter == 1 ? '' : 's' }.',
|
'Button tapped $_counter time${_counter == 1 ? '' : 's'}.',
|
||||||
style: const TextStyle(fontSize: 17.0),
|
style: const TextStyle(fontSize: 17.0),
|
||||||
),
|
),
|
||||||
new Padding(
|
new Padding(
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
flutter:
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
assets:
|
assets:
|
||||||
- assets/flutter-mark-square-64.png
|
- assets/flutter-mark-square-64.png
|
||||||
|
|||||||
11
platform_view_swift/test/widgets_test.dart
Normal file
11
platform_view_swift/test/widgets_test.dart
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// This is a basic Flutter widget test.
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
|
||||||
|
// provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
|
||||||
|
// find child widgets in the widget tree, read text, and verify that the values of widget properties
|
||||||
|
// are correct.
|
||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('This test always passes', (WidgetTester tester) async {});
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ declare -a PROJECT_NAMES=(
|
|||||||
"jsonexample" \
|
"jsonexample" \
|
||||||
"shrine" \
|
"shrine" \
|
||||||
"veggieseasons" \
|
"veggieseasons" \
|
||||||
|
"place_tracker" \
|
||||||
|
"platform_view_swift" \
|
||||||
)
|
)
|
||||||
|
|
||||||
for PROJECT_NAME in "${PROJECT_NAMES[@]}"
|
for PROJECT_NAME in "${PROJECT_NAMES[@]}"
|
||||||
|
|||||||
Reference in New Issue
Block a user