mirror of
https://github.com/flutter/samples.git
synced 2025-11-11 15:28:44 +00:00
Update Navigation and Routing sample (#851)
* Add duration parameter to FadeTransitionPage * Use didChangeDependencies instead of didUpdateWidget * Don't notify listeners if the path hasn't changed * Update navigation sample WIP * Use Link and RouteStateScope in settings screen * update README * use named parameters for Library.addBook() * Make _handleAuthStateChanged synchronous * add missing copyright headers * Address code review comments * Address code review comments
This commit is contained in:
@@ -21,7 +21,7 @@ class BookDetailsScreen extends StatelessWidget {
|
||||
if (book == null) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: Text('No book with found.'),
|
||||
child: Text('No book found.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,20 @@ class _BooksScreenState extends State<BooksScreen>
|
||||
..addListener(_handleTabIndexChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
|
||||
final newPath = routeState.route.pathTemplate;
|
||||
if (newPath.startsWith('/books/popular')) {
|
||||
_tabController.index = 0;
|
||||
} else if (newPath.startsWith('/books/new')) {
|
||||
_tabController.index = 1;
|
||||
} else if (newPath == '/books/all') {
|
||||
_tabController.index = 2;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.removeListener(_handleTabIndexChanged);
|
||||
@@ -114,17 +128,4 @@ class _BooksScreenState extends State<BooksScreen>
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(BooksScreen oldWidget) {
|
||||
var newPath = routeState.route.pathTemplate;
|
||||
if (newPath.startsWith('/books/popular')) {
|
||||
_tabController.index = 0;
|
||||
} else if (newPath.startsWith('/books/new')) {
|
||||
_tabController.index = 1;
|
||||
} else if (newPath == '/books/all') {
|
||||
_tabController.index = 2;
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -15,10 +19,8 @@ import 'scaffold.dart';
|
||||
/// on the [routeState] that was parsed by the TemplateRouteParser.
|
||||
class BookstoreNavigator extends StatefulWidget {
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
final BookstoreAuth auth;
|
||||
|
||||
const BookstoreNavigator({
|
||||
required this.auth,
|
||||
required this.navigatorKey,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
@@ -28,6 +30,7 @@ class BookstoreNavigator extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _BookstoreNavigatorState extends State<BookstoreNavigator> {
|
||||
final signInKey = const ValueKey('Sign in');
|
||||
final scaffoldKey = const ValueKey<String>('App scaffold');
|
||||
final bookDetailsKey = const ValueKey<String>('Book details screen');
|
||||
final authorDetailsKey = const ValueKey<String>('Author details screen');
|
||||
@@ -35,18 +38,19 @@ class _BookstoreNavigatorState extends State<BookstoreNavigator> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final routeState = RouteStateScope.of(context)!;
|
||||
final authState = BookstoreAuthScope.of(context)!;
|
||||
final pathTemplate = routeState.route.pathTemplate;
|
||||
final library = LibraryScope.of(context);
|
||||
|
||||
Book? book;
|
||||
Book? selectedBook;
|
||||
if (pathTemplate == '/book/:bookId') {
|
||||
book = library.allBooks.firstWhereOrNull(
|
||||
selectedBook = library.allBooks.firstWhereOrNull(
|
||||
(b) => b.id.toString() == routeState.route.parameters['bookId']);
|
||||
}
|
||||
|
||||
Author? author;
|
||||
Author? selectedAuthor;
|
||||
if (pathTemplate == '/author/:authorId') {
|
||||
author = library.allAuthors.firstWhereOrNull(
|
||||
selectedAuthor = library.allAuthors.firstWhereOrNull(
|
||||
(b) => b.id.toString() == routeState.route.parameters['authorId']);
|
||||
}
|
||||
|
||||
@@ -71,11 +75,11 @@ class _BookstoreNavigatorState extends State<BookstoreNavigator> {
|
||||
if (routeState.route.pathTemplate == '/signin')
|
||||
// Display the sign in screen.
|
||||
FadeTransitionPage<void>(
|
||||
key: const ValueKey('Sign in'),
|
||||
key: signInKey,
|
||||
child: SignInScreen(
|
||||
onSignIn: (credentials) async {
|
||||
var signedIn = await widget.auth
|
||||
.signIn(credentials.username, credentials.password);
|
||||
var signedIn = await authState.signIn(
|
||||
credentials.username, credentials.password);
|
||||
if (signedIn) {
|
||||
routeState.go('/books/popular');
|
||||
}
|
||||
@@ -90,18 +94,18 @@ class _BookstoreNavigatorState extends State<BookstoreNavigator> {
|
||||
),
|
||||
// Add an additional page to the stack if the user is viewing a book
|
||||
// or an author
|
||||
if (book != null)
|
||||
if (selectedBook != null)
|
||||
MaterialPage<void>(
|
||||
key: bookDetailsKey,
|
||||
child: BookDetailsScreen(
|
||||
book: book,
|
||||
book: selectedBook,
|
||||
),
|
||||
)
|
||||
else if (author != null)
|
||||
else if (selectedAuthor != null)
|
||||
MaterialPage<void>(
|
||||
key: authorDetailsKey,
|
||||
child: AuthorDetailsScreen(
|
||||
author: author,
|
||||
author: selectedAuthor,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:bookstore/src/routing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/link.dart';
|
||||
|
||||
@@ -62,18 +63,15 @@ class SettingsContent extends StatelessWidget {
|
||||
uri: Uri.parse('/book/0'),
|
||||
builder: (context, followLink) {
|
||||
return TextButton(
|
||||
child: const Text('Go directly to /book/0'),
|
||||
child: const Text('Go directly to /book/0 (Link)'),
|
||||
onPressed: followLink,
|
||||
);
|
||||
},
|
||||
),
|
||||
Link(
|
||||
uri: Uri.parse('/author/0'),
|
||||
builder: (context, followLink) {
|
||||
return TextButton(
|
||||
child: const Text('Go directly to /author/0'),
|
||||
onPressed: followLink,
|
||||
);
|
||||
TextButton(
|
||||
child: const Text('Go directly to /book/0 (RouteState)'),
|
||||
onPressed: () {
|
||||
RouteStateScope.of(context)!.go('/book/0');
|
||||
},
|
||||
),
|
||||
].map((w) => Padding(padding: const EdgeInsets.all(8), child: w)),
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
|
||||
class Credentials {
|
||||
final String username;
|
||||
final String password;
|
||||
|
||||
Credentials(this.username, this.password);
|
||||
}
|
||||
|
||||
@@ -24,8 +25,8 @@ class SignInScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SignInScreenState extends State<SignInScreen> {
|
||||
String username = '';
|
||||
String password = '';
|
||||
final _usernameController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -42,26 +43,20 @@ class _SignInScreenState extends State<SignInScreen> {
|
||||
Text('Sign in', style: Theme.of(context).textTheme.headline4),
|
||||
TextField(
|
||||
decoration: const InputDecoration(labelText: 'Username'),
|
||||
onChanged: (v) {
|
||||
setState(() {
|
||||
username = v;
|
||||
});
|
||||
},
|
||||
controller: _usernameController,
|
||||
),
|
||||
TextField(
|
||||
decoration: const InputDecoration(labelText: 'Password'),
|
||||
obscureText: true,
|
||||
onChanged: (v) {
|
||||
setState(() {
|
||||
password = v;
|
||||
});
|
||||
},
|
||||
controller: _passwordController,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
widget.onSignIn(Credentials(username, password));
|
||||
widget.onSignIn(Credentials(
|
||||
_usernameController.value.text,
|
||||
_passwordController.value.text));
|
||||
},
|
||||
child: const Text('Sign in'),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user