1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-08 13:58:47 +00:00

Flutter 3.29 beta (#2571)

This commit is contained in:
Eric Windmill
2025-02-12 18:08:01 -05:00
committed by GitHub
parent d62c784789
commit 719fd72c38
685 changed files with 76244 additions and 53721 deletions

View File

@@ -8,8 +8,10 @@ import 'package:provider/provider.dart';
import 'place_tracker_app.dart';
void main() {
runApp(ChangeNotifierProvider(
create: (context) => AppState(),
child: const PlaceTrackerApp(),
));
runApp(
ChangeNotifierProvider(
create: (context) => AppState(),
child: const PlaceTrackerApp(),
),
);
}

View File

@@ -65,8 +65,4 @@ class Place {
starRating.hashCode;
}
enum PlaceCategory {
favorite,
visited,
wantToGo,
}
enum PlaceCategory { favorite, visited, wantToGo }

View File

@@ -13,10 +13,7 @@ import 'stub_data.dart';
class PlaceDetails extends StatefulWidget {
final Place place;
const PlaceDetails({
required this.place,
super.key,
});
const PlaceDetails({required this.place, super.key});
@override
State<PlaceDetails> createState() => _PlaceDetailsState();
@@ -107,10 +104,12 @@ class _PlaceDetailsState extends State<PlaceDetails> {
void _onMapCreated(GoogleMapController controller) {
_mapController = controller;
setState(() {
_markers.add(Marker(
markerId: MarkerId(_place.latLng.toString()),
position: _place.latLng,
));
_markers.add(
Marker(
markerId: MarkerId(_place.latLng.toString()),
position: _place.latLng,
),
);
});
}
@@ -179,10 +178,7 @@ class _Map extends StatelessWidget {
height: 240,
child: GoogleMap(
onMapCreated: onMapCreated,
initialCameraPosition: CameraPosition(
target: center,
zoom: 16,
),
initialCameraPosition: CameraPosition(target: center, zoom: 16),
markers: markers,
zoomGesturesEnabled: false,
rotateGesturesEnabled: false,
@@ -199,10 +195,7 @@ class _NameTextField extends StatelessWidget {
final ValueChanged<String> onChanged;
const _NameTextField({
required this.controller,
required this.onChanged,
});
const _NameTextField({required this.controller, required this.onChanged});
@override
Widget build(BuildContext context) {
@@ -247,9 +240,10 @@ class _Reviews extends StatelessWidget {
),
),
Column(
children: StubData.reviewStrings
.map((reviewText) => _buildSingleReview(reviewText))
.toList(),
children:
StubData.reviewStrings
.map((reviewText) => _buildSingleReview(reviewText))
.toList(),
),
],
);
@@ -267,10 +261,7 @@ class _Reviews extends StatelessWidget {
height: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
border: Border.all(
width: 3,
color: Colors.grey,
),
border: Border.all(width: 3, color: Colors.grey),
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
@@ -283,11 +274,7 @@ class _Reviews extends StatelessWidget {
color: Colors.black87,
),
),
Icon(
Icons.star,
color: Colors.amber,
size: 36,
),
Icon(Icons.star, color: Colors.amber, size: 36),
],
),
),
@@ -302,10 +289,7 @@ class _Reviews extends StatelessWidget {
],
),
),
Divider(
height: 8,
color: Colors.grey[700],
),
Divider(height: 8, color: Colors.grey[700]),
],
);
}
@@ -317,25 +301,24 @@ class _StarBar extends StatelessWidget {
final int rating;
final ValueChanged<int> onChanged;
const _StarBar({
required this.rating,
required this.onChanged,
}) : assert(rating >= 0 && rating <= maxStars);
const _StarBar({required this.rating, required this.onChanged})
: assert(rating >= 0 && rating <= maxStars);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(maxStars, (index) {
return IconButton(
icon: const Icon(Icons.star),
iconSize: 40,
color: rating > index ? Colors.amber : Colors.grey[400],
onPressed: () {
onChanged(index + 1);
},
);
}).toList(),
children:
List.generate(maxStars, (index) {
return IconButton(
icon: const Icon(Icons.star),
iconSize: 40,
color: rating > index ? Colors.amber : Colors.grey[400],
onPressed: () {
onChanged(index + 1);
},
);
}).toList(),
);
}
}

View File

@@ -33,10 +33,11 @@ class _PlaceListState extends State<PlaceList> {
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 8.0),
controller: _scrollController,
shrinkWrap: true,
children: state.places
.where((place) => place.category == state.selectedCategory)
.map((place) => _PlaceListTile(place: place))
.toList(),
children:
state.places
.where((place) => place.category == state.selectedCategory)
.map((place) => _PlaceListTile(place: place))
.toList(),
),
),
],
@@ -45,8 +46,10 @@ class _PlaceListState extends State<PlaceList> {
void _onCategoryChanged(PlaceCategory newCategory) {
_scrollController.jumpTo(0.0);
Provider.of<AppState>(context, listen: false)
.setSelectedCategory(newCategory);
Provider.of<AppState>(
context,
listen: false,
).setSelectedCategory(newCategory);
}
}
@@ -67,7 +70,7 @@ class _CategoryButton extends StatelessWidget {
final buttonText = switch (category) {
PlaceCategory.favorite => 'Favorites',
PlaceCategory.visited => 'Visited',
PlaceCategory.wantToGo => 'Want To Go'
PlaceCategory.wantToGo => 'Want To Go',
};
return Container(
@@ -134,9 +137,7 @@ class _ListCategoryButtonBar extends StatelessWidget {
class _PlaceListTile extends StatelessWidget {
final Place place;
const _PlaceListTile({
required this.place,
});
const _PlaceListTile({required this.place});
@override
Widget build(BuildContext context) {
@@ -157,15 +158,17 @@ class _PlaceListTile extends StatelessWidget {
maxLines: 3,
),
Row(
children: List.generate(5, (index) {
return Icon(
Icons.star,
size: 28.0,
color: place.starRating > index
? Colors.amber
: Colors.grey[400],
);
}).toList(),
children:
List.generate(5, (index) {
return Icon(
Icons.star,
size: 28.0,
color:
place.starRating > index
? Colors.amber
: Colors.grey[400],
);
}).toList(),
),
Text(
place.description ?? '',
@@ -174,10 +177,7 @@ class _PlaceListTile extends StatelessWidget {
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 16.0),
Divider(
height: 2.0,
color: Colors.grey[700],
),
Divider(height: 2.0, color: Colors.grey[700]),
],
),
),

View File

@@ -54,10 +54,7 @@ class MapConfiguration {
class PlaceMap extends StatefulWidget {
final LatLng? center;
const PlaceMap({
super.key,
this.center,
});
const PlaceMap({super.key, this.center});
@override
State<PlaceMap> createState() => _PlaceMapState();
@@ -94,43 +91,45 @@ class _PlaceMapState extends State<PlaceMap> {
Widget build(BuildContext context) {
_watchMapConfigurationChanges();
var state = Provider.of<AppState>(context, listen: true);
return Builder(builder: (context) {
// We need this additional builder here so that we can pass its context to
// _AddPlaceButtonBar's onSavePressed callback. This callback shows a
// SnackBar and to do this, we need a build context that has Scaffold as
// an ancestor.
return Center(
child: Stack(
children: [
GoogleMap(
onMapCreated: onMapCreated,
initialCameraPosition: CameraPosition(
target: widget.center!,
zoom: 11.0,
return Builder(
builder: (context) {
// We need this additional builder here so that we can pass its context to
// _AddPlaceButtonBar's onSavePressed callback. This callback shows a
// SnackBar and to do this, we need a build context that has Scaffold as
// an ancestor.
return Center(
child: Stack(
children: [
GoogleMap(
onMapCreated: onMapCreated,
initialCameraPosition: CameraPosition(
target: widget.center!,
zoom: 11.0,
),
mapType: _currentMapType,
markers: _markers,
onCameraMove: (position) => _lastMapPosition = position.target,
),
mapType: _currentMapType,
markers: _markers,
onCameraMove: (position) => _lastMapPosition = position.target,
),
_CategoryButtonBar(
selectedPlaceCategory: state.selectedCategory,
visible: _pendingMarker == null,
onChanged: _switchSelectedCategory,
),
_AddPlaceButtonBar(
visible: _pendingMarker != null,
onSavePressed: () => _confirmAddPlace(context),
onCancelPressed: _cancelAddPlace,
),
_MapFabs(
visible: _pendingMarker == null,
onAddPlacePressed: _onAddPlacePressed,
onToggleMapTypePressed: _onToggleMapTypePressed,
),
],
),
);
});
_CategoryButtonBar(
selectedPlaceCategory: state.selectedCategory,
visible: _pendingMarker == null,
onChanged: _switchSelectedCategory,
),
_AddPlaceButtonBar(
visible: _pendingMarker != null,
onSavePressed: () => _confirmAddPlace(context),
onCancelPressed: _cancelAddPlace,
),
_MapFabs(
visible: _pendingMarker == null,
onAddPlacePressed: _onAddPlacePressed,
onToggleMapTypePressed: _onToggleMapTypePressed,
),
],
),
);
},
);
}
Future<void> onMapCreated(GoogleMapController controller) async {
@@ -221,8 +220,10 @@ class _PlaceMapState extends State<PlaceMap> {
scaffoldMessenger.showSnackBar(
SnackBar(
duration: const Duration(seconds: 3),
content:
const Text('New place added.', style: TextStyle(fontSize: 16.0)),
content: const Text(
'New place added.',
style: TextStyle(fontSize: 16.0),
),
action: SnackBarAction(
label: 'Edit',
onPressed: () async {
@@ -278,8 +279,9 @@ class _PlaceMapState extends State<PlaceMap> {
// At this point, we know the places have been updated from the list
// view. We need to reconfigure the map to respect the updates.
for (final place in newConfiguration.places) {
final oldPlace =
_configuration!.places.firstWhereOrNull((p) => p.id == place.id);
final oldPlace = _configuration!.places.firstWhereOrNull(
(p) => p.id == place.id,
);
if (oldPlace == null || oldPlace != place) {
// New place or updated place.
_updateExistingPlaceMarker(place: place);
@@ -336,10 +338,9 @@ class _PlaceMapState extends State<PlaceMap> {
}
});
await _zoomToFitPlaces(_getPlacesForCategory(
category,
_markedPlaces.values.toList(),
));
await _zoomToFitPlaces(
_getPlacesForCategory(category, _markedPlaces.values.toList()),
);
}
Future<void> _switchSelectedCategory(PlaceCategory category) async {
@@ -348,8 +349,9 @@ class _PlaceMapState extends State<PlaceMap> {
}
void _updateExistingPlaceMarker({required Place place}) {
var marker = _markedPlaces.keys
.singleWhere((value) => _markedPlaces[value]!.id == place.id);
var marker = _markedPlaces.keys.singleWhere(
(value) => _markedPlaces[value]!.id == place.id,
);
setState(() {
final updatedMarker = marker.copyWith(
@@ -407,16 +409,20 @@ class _PlaceMapState extends State<PlaceMap> {
Future<BitmapDescriptor> _getPlaceMarkerIcon(PlaceCategory category) =>
switch (category) {
PlaceCategory.favorite => BitmapDescriptor.asset(
createLocalImageConfiguration(context, size: const Size.square(32)),
'assets/heart.png'),
createLocalImageConfiguration(context, size: const Size.square(32)),
'assets/heart.png',
),
PlaceCategory.visited => BitmapDescriptor.asset(
createLocalImageConfiguration(context, size: const Size.square(32)),
'assets/visited.png'),
createLocalImageConfiguration(context, size: const Size.square(32)),
'assets/visited.png',
),
PlaceCategory.wantToGo => Future.value(BitmapDescriptor.defaultMarker),
};
static List<Place> _getPlacesForCategory(
PlaceCategory category, List<Place> places) {
PlaceCategory category,
List<Place> places,
) {
return places.where((place) => place.category == category).toList();
}
}
@@ -496,10 +502,11 @@ class _CategoryButtonBar extends StatelessWidget {
children: <Widget>[
FilledButton(
style: FilledButton.styleFrom(
backgroundColor:
selectedPlaceCategory == PlaceCategory.favorite
? Colors.green[700]
: Colors.lightGreen),
backgroundColor:
selectedPlaceCategory == PlaceCategory.favorite
? Colors.green[700]
: Colors.lightGreen,
),
onPressed: () => onChanged(PlaceCategory.favorite),
child: const Text(
'Favorites',
@@ -508,10 +515,11 @@ class _CategoryButtonBar extends StatelessWidget {
),
FilledButton(
style: FilledButton.styleFrom(
backgroundColor:
selectedPlaceCategory == PlaceCategory.visited
? Colors.green[700]
: Colors.lightGreen),
backgroundColor:
selectedPlaceCategory == PlaceCategory.visited
? Colors.green[700]
: Colors.lightGreen,
),
onPressed: () => onChanged(PlaceCategory.visited),
child: const Text(
'Visited',
@@ -520,10 +528,11 @@ class _CategoryButtonBar extends StatelessWidget {
),
FilledButton(
style: FilledButton.styleFrom(
backgroundColor:
selectedPlaceCategory == PlaceCategory.wantToGo
? Colors.green[700]
: Colors.lightGreen),
backgroundColor:
selectedPlaceCategory == PlaceCategory.wantToGo
? Colors.green[700]
: Colors.lightGreen,
),
onPressed: () => onChanged(PlaceCategory.wantToGo),
child: const Text(
'Want To Go',

View File

@@ -13,10 +13,7 @@ import 'place_list.dart';
import 'place_map.dart';
import 'stub_data.dart';
enum PlaceTrackerViewType {
map,
list,
}
enum PlaceTrackerViewType { map, list }
class PlaceTrackerApp extends StatelessWidget {
const PlaceTrackerApp({super.key});
@@ -35,25 +32,26 @@ class PlaceTrackerApp extends StatelessWidget {
foregroundColor: Colors.white,
),
),
routerConfig: GoRouter(routes: [
GoRoute(
path: '/',
builder: (context, state) => const _PlaceTrackerHomePage(),
routes: [
GoRoute(
path: 'place/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
final place = context
.read<AppState>()
.places
.singleWhere((place) => place.id == id);
return PlaceDetails(place: place);
},
),
],
),
]),
routerConfig: GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const _PlaceTrackerHomePage(),
routes: [
GoRoute(
path: 'place/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
final place = context.read<AppState>().places.singleWhere(
(place) => place.id == id,
);
return PlaceDetails(place: place);
},
),
],
),
],
),
);
}
}
@@ -101,7 +99,7 @@ class _PlaceTrackerHomePage extends StatelessWidget {
index: state.viewType == PlaceTrackerViewType.map ? 0 : 1,
children: const [
PlaceMap(center: LatLng(45.521563, -122.677433)),
PlaceList()
PlaceList(),
],
),
);

View File

@@ -148,6 +148,6 @@ class StubData {
static const reviewStrings = [
'My favorite place in Portland. The employees are wonderful and so is the food. I go here at least once a month!',
'Staff was very friendly. Great atmosphere and good music. Would recommend.',
'Best. Place. In. Town. Period.'
'Best. Place. In. Town. Period.',
];
}

View File

@@ -4,7 +4,7 @@ description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ^3.5.0
sdk: ^3.7.0-0
dependencies:
flutter: