Add list view to place tracker. Note: map in listTile is not WAI in this commit.

pull/30/head
kenzieschmoll 8 years ago
parent 7ab277fad4
commit b95215fb00

@ -0,0 +1,216 @@
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'place.dart';
class PlaceList extends StatefulWidget {
const PlaceList({
@required this.places,
@required this.selectedCategory,
@required this.onCategoryChanged,
Key key,
}) : assert(places != null),
super(key: key);
final List<Place> places;
final PlaceCategory selectedCategory;
final ValueChanged<PlaceCategory> onCategoryChanged;
@override
PlaceListState createState() => PlaceListState();
}
class PlaceListState extends State<PlaceList> {
ScrollController _scrollController = ScrollController();
void _onCategoryChanged(PlaceCategory newCategory) {
_scrollController.jumpTo(0.0);
widget.onCategoryChanged(newCategory);
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
_ListCategoryButtonBar(
selectedCategory: widget.selectedCategory,
onCategoryChanged: (value) => _onCategoryChanged(value),
),
Expanded(
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
controller: _scrollController,
shrinkWrap: true,
children: widget.places.map((Place place) => _PlaceListTile(place: place)).toList(),
),
),
],
);
}
}
class _PlaceListTile extends StatelessWidget {
const _PlaceListTile({
Key key,
@required this.place
}) : assert(place != null),
super(key: key);
final Place place;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
place.name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
),
maxLines: 3,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: List.generate(5, (int index) {
return Icon(Icons.star,
size: 28.0,
color: place.starRating > index ? Colors.amber : Colors.grey[400],
);
}).toList(),
),
Text(
place.description != null ? place.description : '',
style: Theme.of(context).textTheme.subhead,
maxLines: 4,
overflow: TextOverflow.ellipsis,
),
],
),
),
),
_Map(center: place.latLng),
],
),
Divider(
height: 36.0,
color: Colors.grey[700],
),
],
);
}
}
class _Map extends StatelessWidget {
const _Map({
@required this.center,
Key key,
}) : assert(center != null),
super(key: key);
final LatLng center;
_onMapCreated(GoogleMapController controller) {
controller.addMarker(
MarkerOptions(
position: center,
),
);
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: 140.0,
width: 160.0,
child: GoogleMap(
onMapCreated: _onMapCreated,
options: GoogleMapOptions(
cameraPosition: CameraPosition(
target: center,
zoom: 17.0,
),
zoomGesturesEnabled: false,
rotateGesturesEnabled: false,
tiltGesturesEnabled: false,
scrollGesturesEnabled: false,
),
),
);
}
}
class _ListCategoryButtonBar extends StatelessWidget {
const _ListCategoryButtonBar({
@required this.selectedCategory,
@required this.onCategoryChanged,
Key key,
})
: assert(selectedCategory != null),
assert(onCategoryChanged != null),
super(key: key);
final PlaceCategory selectedCategory;
final ValueChanged<PlaceCategory> onCategoryChanged;
Widget _buildButtonForCategory(PlaceCategory category) {
String _buttonText;
switch (category) {
case PlaceCategory.favorite:
_buttonText = 'Favorites';
break;
case PlaceCategory.visited:
_buttonText = 'Visited';
break;
case PlaceCategory.wantToGo:
_buttonText = 'Want To Go';
}
return Container(
margin: EdgeInsets.symmetric(vertical: 12.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: selectedCategory == category ? Colors.blue : Colors.transparent,
),
),
),
child: ButtonTheme(
height: 50.0,
child: FlatButton(
child: Text(
_buttonText,
style: TextStyle(
fontSize: selectedCategory == category ? 20.0 : 18.0,
color: selectedCategory == category ? Colors.blue : Colors.black87,
),
),
onPressed: () => onCategoryChanged(category),
),
),
);
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildButtonForCategory(PlaceCategory.favorite),
_buildButtonForCategory(PlaceCategory.visited),
_buildButtonForCategory(PlaceCategory.wantToGo),
],
);
}
}

@ -6,6 +6,12 @@ import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'place.dart'; import 'place.dart';
import 'place_stub_data.dart'; import 'place_stub_data.dart';
import 'place_details.dart'; import 'place_details.dart';
import 'place_list.dart';
enum PlaceTrackerViewType {
map,
list,
}
class PlaceMap extends StatefulWidget { class PlaceMap extends StatefulWidget {
const PlaceMap({ const PlaceMap({
@ -43,9 +49,10 @@ class PlaceMapState extends State<PlaceMap> {
} }
GoogleMapController mapController; GoogleMapController mapController;
PlaceCategory _selectedPlaceCategory = PlaceCategory.favorite;
Map<Marker, Place> _places = Map<Marker, Place>();
Marker _pendingMarker; Marker _pendingMarker;
Map<Marker, Place> _places = Map<Marker, Place>();
PlaceCategory _selectedPlaceCategory = PlaceCategory.favorite;
PlaceTrackerViewType viewType = PlaceTrackerViewType.map;
void onMapCreated(GoogleMapController controller) async { void onMapCreated(GoogleMapController controller) async {
mapController = controller; mapController = controller;
@ -122,7 +129,7 @@ class PlaceMapState extends State<PlaceMap> {
); );
} }
void _updatePlaces(PlaceCategory category) { void _updateDisplayedPlaces(PlaceCategory category) {
setState(() { setState(() {
_selectedPlaceCategory = category; _selectedPlaceCategory = category;
_showPlacesForSelectedCategory(); _showPlacesForSelectedCategory();
@ -234,27 +241,26 @@ class PlaceMapState extends State<PlaceMap> {
} }
} }
@override void _switchViewType() {
Widget build(BuildContext context) { switch (viewType) {
return Scaffold( case PlaceTrackerViewType.map:
appBar: AppBar( setState(() {
title: Row( viewType = PlaceTrackerViewType.list;
crossAxisAlignment: CrossAxisAlignment.center, });
children: const <Widget>[ break;
Padding( case PlaceTrackerViewType.list:
padding: EdgeInsets.fromLTRB(0.0, 0.0, 8.0, 0.0), setState(() {
child: Icon(Icons.pin_drop, size: 24.0), viewType = PlaceTrackerViewType.map;
), });
Text('Place Tracker'), }
], }
),
backgroundColor: Colors.green[700], Widget _placeMap() {
), return Builder(builder: (BuildContext context) {
// We need this additional builder here so that we can pass its context to // We need this additional builder here so that we can pass its context to
// _AddPlaceButtonBar's onSavePressed callback. This callback shows a // _AddPlaceButtonBar's onSavePressed callback. This callback shows a
// SnackBar and to do this, we need a build context that has Scaffold as // SnackBar and to do this, we need a build context that has Scaffold as
// an ancestor. // an ancestor.
body: Builder(builder: (BuildContext context) {
return Center( return Center(
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
@ -271,7 +277,7 @@ class PlaceMapState extends State<PlaceMap> {
_CategoryButtonBar( _CategoryButtonBar(
selectedPlaceCategory: _selectedPlaceCategory, selectedPlaceCategory: _selectedPlaceCategory,
visible: _pendingMarker == null, visible: _pendingMarker == null,
onChanged: _updatePlaces, onChanged: _updateDisplayedPlaces,
), ),
_AddPlaceButtonBar( _AddPlaceButtonBar(
visible: _pendingMarker != null, visible: _pendingMarker != null,
@ -285,7 +291,59 @@ class PlaceMapState extends State<PlaceMap> {
], ],
), ),
); );
}), });
}
Widget _placeList() {
return PlaceList(
places: _getPlacesForCategory(_selectedPlaceCategory, _places),
selectedCategory: _selectedPlaceCategory,
onCategoryChanged: (PlaceCategory value) {
setState(() {
_selectedPlaceCategory = value;
_updateDisplayedPlaces(_selectedPlaceCategory);
});
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: const <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 8.0, 0.0),
child: Icon(Icons.pin_drop, size: 24.0),
),
Text('Place Tracker'),
],
),
backgroundColor: Colors.green[700],
actions: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 16.0, 0.0),
child: IconButton(
icon: Icon(
viewType == PlaceTrackerViewType.map
? Icons.list
: Icons.map,
size: 32.0
),
onPressed: _switchViewType,
),
),
],
),
body: IndexedStack(
index: viewType == PlaceTrackerViewType.map ? 0 : 1,
children: <Widget>[
_placeMap(),
_placeList(),
],
),
); );
} }
} }
@ -417,7 +475,7 @@ class _AddPlaceFab extends StatelessWidget {
return Opacity( return Opacity(
opacity: visible ? 1.0 : 0.0, opacity: visible ? 1.0 : 0.0,
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(12.0),
child: Align( child: Align(
alignment: Alignment.topRight, alignment: Alignment.topRight,
child: FloatingActionButton( child: FloatingActionButton(

Loading…
Cancel
Save