Updates travis config to include place_tracker and platform_view_swift (#42)

pull/45/head
Andrew Brogdon 6 years ago committed by GitHub
parent 6ce0d22e9b
commit e67cbb03ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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,
), ),

@ -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

@ -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[@]}"

Loading…
Cancel
Save