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:
@@ -37,11 +37,13 @@ void setupWindow() {
|
||||
setWindowMinSize(const Size(windowWidth, windowHeight));
|
||||
setWindowMaxSize(const Size(windowWidth, windowHeight));
|
||||
getCurrentScreen().then((screen) {
|
||||
setWindowFrame(Rect.fromCenter(
|
||||
center: screen!.frame.center,
|
||||
width: windowWidth,
|
||||
height: windowHeight,
|
||||
));
|
||||
setWindowFrame(
|
||||
Rect.fromCenter(
|
||||
center: screen!.frame.center,
|
||||
width: windowWidth,
|
||||
height: windowHeight,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,10 +37,7 @@ class _BookstoreState extends State<Bookstore> {
|
||||
if (child == null) {
|
||||
throw ('No child in .router constructor builder');
|
||||
}
|
||||
return BookstoreAuthScope(
|
||||
notifier: auth,
|
||||
child: child,
|
||||
);
|
||||
return BookstoreAuthScope(notifier: auth, child: child);
|
||||
},
|
||||
routerConfig: GoRouter(
|
||||
refreshListenable: auth,
|
||||
@@ -74,25 +71,27 @@ class _BookstoreState extends State<Bookstore> {
|
||||
key: state.pageKey,
|
||||
// Use a builder to get the correct BuildContext
|
||||
// TODO (johnpryan): remove when https://github.com/flutter/flutter/issues/108177 lands
|
||||
child: Builder(builder: (context) {
|
||||
return BooksScreen(
|
||||
onTap: (idx) {
|
||||
GoRouter.of(context).go(switch (idx) {
|
||||
0 => '/books/popular',
|
||||
1 => '/books/new',
|
||||
2 => '/books/all',
|
||||
_ => '/books/popular',
|
||||
});
|
||||
},
|
||||
selectedIndex: switch (state.uri.path) {
|
||||
var p when p.startsWith('/books/popular') => 0,
|
||||
var p when p.startsWith('/books/new') => 1,
|
||||
var p when p.startsWith('/books/all') => 2,
|
||||
_ => 0,
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return BooksScreen(
|
||||
onTap: (idx) {
|
||||
GoRouter.of(context).go(switch (idx) {
|
||||
0 => '/books/popular',
|
||||
1 => '/books/new',
|
||||
2 => '/books/all',
|
||||
_ => '/books/popular',
|
||||
});
|
||||
},
|
||||
selectedIndex: switch (state.uri.path) {
|
||||
var p when p.startsWith('/books/popular') => 0,
|
||||
var p when p.startsWith('/books/new') => 1,
|
||||
var p when p.startsWith('/books/all') => 2,
|
||||
_ => 0,
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
routes: [
|
||||
@@ -108,8 +107,9 @@ class _BookstoreState extends State<Bookstore> {
|
||||
return BookList(
|
||||
books: libraryInstance.popularBooks,
|
||||
onTap: (book) {
|
||||
GoRouter.of(context)
|
||||
.go('/books/popular/book/${book.id}');
|
||||
GoRouter.of(
|
||||
context,
|
||||
).go('/books/popular/book/${book.id}');
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -122,8 +122,9 @@ class _BookstoreState extends State<Bookstore> {
|
||||
parentNavigatorKey: appShellNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return BookDetailsScreen(
|
||||
book: libraryInstance
|
||||
.getBook(state.pathParameters['bookId'] ?? ''),
|
||||
book: libraryInstance.getBook(
|
||||
state.pathParameters['bookId'] ?? '',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -141,8 +142,9 @@ class _BookstoreState extends State<Bookstore> {
|
||||
return BookList(
|
||||
books: libraryInstance.newBooks,
|
||||
onTap: (book) {
|
||||
GoRouter.of(context)
|
||||
.go('/books/new/book/${book.id}');
|
||||
GoRouter.of(
|
||||
context,
|
||||
).go('/books/new/book/${book.id}');
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -155,8 +157,9 @@ class _BookstoreState extends State<Bookstore> {
|
||||
parentNavigatorKey: appShellNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return BookDetailsScreen(
|
||||
book: libraryInstance
|
||||
.getBook(state.pathParameters['bookId'] ?? ''),
|
||||
book: libraryInstance.getBook(
|
||||
state.pathParameters['bookId'] ?? '',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -174,8 +177,9 @@ class _BookstoreState extends State<Bookstore> {
|
||||
return BookList(
|
||||
books: libraryInstance.allBooks,
|
||||
onTap: (book) {
|
||||
GoRouter.of(context)
|
||||
.go('/books/all/book/${book.id}');
|
||||
GoRouter.of(
|
||||
context,
|
||||
).go('/books/all/book/${book.id}');
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -188,8 +192,9 @@ class _BookstoreState extends State<Bookstore> {
|
||||
parentNavigatorKey: appShellNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return BookDetailsScreen(
|
||||
book: libraryInstance
|
||||
.getBook(state.pathParameters['bookId'] ?? ''),
|
||||
book: libraryInstance.getBook(
|
||||
state.pathParameters['bookId'] ?? '',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -202,14 +207,17 @@ class _BookstoreState extends State<Bookstore> {
|
||||
pageBuilder: (context, state) {
|
||||
return FadeTransitionPage<dynamic>(
|
||||
key: state.pageKey,
|
||||
child: Builder(builder: (context) {
|
||||
return AuthorsScreen(
|
||||
onTap: (author) {
|
||||
GoRouter.of(context)
|
||||
.go('/authors/author/${author.id}');
|
||||
},
|
||||
);
|
||||
}),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return AuthorsScreen(
|
||||
onTap: (author) {
|
||||
GoRouter.of(
|
||||
context,
|
||||
).go('/authors/author/${author.id}');
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
routes: [
|
||||
@@ -217,22 +225,26 @@ class _BookstoreState extends State<Bookstore> {
|
||||
path: 'author/:authorId',
|
||||
builder: (context, state) {
|
||||
final author = libraryInstance.allAuthors.firstWhere(
|
||||
(author) =>
|
||||
author.id ==
|
||||
int.parse(state.pathParameters['authorId']!));
|
||||
(author) =>
|
||||
author.id ==
|
||||
int.parse(state.pathParameters['authorId']!),
|
||||
);
|
||||
// Use a builder to get the correct BuildContext
|
||||
// TODO (johnpryan): remove when https://github.com/flutter/flutter/issues/108177 lands
|
||||
return Builder(builder: (context) {
|
||||
return AuthorDetailsScreen(
|
||||
author: author,
|
||||
onBookTapped: (book) {
|
||||
GoRouter.of(context)
|
||||
.go('/books/all/book/${book.id}');
|
||||
},
|
||||
);
|
||||
});
|
||||
return Builder(
|
||||
builder: (context) {
|
||||
return AuthorDetailsScreen(
|
||||
author: author,
|
||||
onBookTapped: (book) {
|
||||
GoRouter.of(
|
||||
context,
|
||||
).go('/books/all/book/${book.id}');
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
GoRoute(
|
||||
@@ -256,8 +268,9 @@ class _BookstoreState extends State<Bookstore> {
|
||||
return SignInScreen(
|
||||
onSignIn: (value) async {
|
||||
final router = GoRouter.of(context);
|
||||
await BookstoreAuth.of(context)
|
||||
.signIn(value.username, value.password);
|
||||
await BookstoreAuth.of(
|
||||
context,
|
||||
).signIn(value.username, value.password);
|
||||
router.go('/books/popular');
|
||||
},
|
||||
);
|
||||
|
||||
@@ -33,9 +33,10 @@ class BookstoreAuth extends ChangeNotifier {
|
||||
@override
|
||||
int get hashCode => _signedIn.hashCode;
|
||||
|
||||
static BookstoreAuth of(BuildContext context) => context
|
||||
.dependOnInheritedWidgetOfExactType<BookstoreAuthScope>()!
|
||||
.notifier!;
|
||||
static BookstoreAuth of(BuildContext context) =>
|
||||
context
|
||||
.dependOnInheritedWidgetOfExactType<BookstoreAuthScope>()!
|
||||
.notifier!;
|
||||
}
|
||||
|
||||
class BookstoreAuthScope extends InheritedNotifier<BookstoreAuth> {
|
||||
|
||||
@@ -5,27 +5,32 @@
|
||||
import 'author.dart';
|
||||
import 'book.dart';
|
||||
|
||||
final libraryInstance = Library()
|
||||
..addBook(
|
||||
title: 'Left Hand of Darkness',
|
||||
authorName: 'Ursula K. Le Guin',
|
||||
isPopular: true,
|
||||
isNew: true)
|
||||
..addBook(
|
||||
title: 'Too Like the Lightning',
|
||||
authorName: 'Ada Palmer',
|
||||
isPopular: false,
|
||||
isNew: true)
|
||||
..addBook(
|
||||
title: 'Kindred',
|
||||
authorName: 'Octavia E. Butler',
|
||||
isPopular: true,
|
||||
isNew: false)
|
||||
..addBook(
|
||||
title: 'The Lathe of Heaven',
|
||||
authorName: 'Ursula K. Le Guin',
|
||||
isPopular: false,
|
||||
isNew: false);
|
||||
final libraryInstance =
|
||||
Library()
|
||||
..addBook(
|
||||
title: 'Left Hand of Darkness',
|
||||
authorName: 'Ursula K. Le Guin',
|
||||
isPopular: true,
|
||||
isNew: true,
|
||||
)
|
||||
..addBook(
|
||||
title: 'Too Like the Lightning',
|
||||
authorName: 'Ada Palmer',
|
||||
isPopular: false,
|
||||
isNew: true,
|
||||
)
|
||||
..addBook(
|
||||
title: 'Kindred',
|
||||
authorName: 'Octavia E. Butler',
|
||||
isPopular: true,
|
||||
isNew: false,
|
||||
)
|
||||
..addBook(
|
||||
title: 'The Lathe of Heaven',
|
||||
authorName: 'Ursula K. Le Guin',
|
||||
isPopular: false,
|
||||
isNew: false,
|
||||
);
|
||||
|
||||
class Library {
|
||||
final List<Book> allBooks = [];
|
||||
@@ -55,11 +60,7 @@ class Library {
|
||||
return allBooks[int.parse(id)];
|
||||
}
|
||||
|
||||
List<Book> get popularBooks => [
|
||||
...allBooks.where((book) => book.isPopular),
|
||||
];
|
||||
List<Book> get popularBooks => [...allBooks.where((book) => book.isPopular)];
|
||||
|
||||
List<Book> get newBooks => [
|
||||
...allBooks.where((book) => book.isNew),
|
||||
];
|
||||
List<Book> get newBooks => [...allBooks.where((book) => book.isNew)];
|
||||
}
|
||||
|
||||
@@ -19,22 +19,20 @@ class AuthorDetailsScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(author.name),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BookList(
|
||||
books: author.books,
|
||||
onTap: (book) {
|
||||
onBookTapped(book);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
appBar: AppBar(title: Text(author.name)),
|
||||
body: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BookList(
|
||||
books: author.books,
|
||||
onTap: (book) {
|
||||
onBookTapped(book);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,20 +12,11 @@ class AuthorsScreen extends StatelessWidget {
|
||||
final String title;
|
||||
final ValueChanged<Author> onTap;
|
||||
|
||||
const AuthorsScreen({
|
||||
required this.onTap,
|
||||
this.title = 'Authors',
|
||||
super.key,
|
||||
});
|
||||
const AuthorsScreen({required this.onTap, this.title = 'Authors', super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(title),
|
||||
),
|
||||
body: AuthorList(
|
||||
authors: libraryInstance.allAuthors,
|
||||
onTap: onTap,
|
||||
),
|
||||
);
|
||||
appBar: AppBar(title: Text(title)),
|
||||
body: AuthorList(authors: libraryInstance.allAuthors, onTap: onTap),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,24 +12,15 @@ import 'author_details.dart';
|
||||
class BookDetailsScreen extends StatelessWidget {
|
||||
final Book? book;
|
||||
|
||||
const BookDetailsScreen({
|
||||
super.key,
|
||||
this.book,
|
||||
});
|
||||
const BookDetailsScreen({super.key, this.book});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (book == null) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: Text('No book found.'),
|
||||
),
|
||||
);
|
||||
return const Scaffold(body: Center(child: Text('No book found.')));
|
||||
}
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(book!.title),
|
||||
),
|
||||
appBar: AppBar(title: Text(book!.title)),
|
||||
body: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -46,22 +37,26 @@ class BookDetailsScreen extends StatelessWidget {
|
||||
onPressed: () {
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (context) => AuthorDetailsScreen(
|
||||
author: book!.author,
|
||||
onBookTapped: (book) {
|
||||
GoRouter.of(context).go('/books/all/book/${book.id}');
|
||||
},
|
||||
),
|
||||
builder:
|
||||
(context) => AuthorDetailsScreen(
|
||||
author: book!.author,
|
||||
onBookTapped: (book) {
|
||||
GoRouter.of(
|
||||
context,
|
||||
).go('/books/all/book/${book.id}');
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Link(
|
||||
uri: Uri.parse('/authors/author/${book!.author.id}'),
|
||||
builder: (context, followLink) => TextButton(
|
||||
onPressed: followLink,
|
||||
child: const Text('View author (Link)'),
|
||||
),
|
||||
builder:
|
||||
(context, followLink) => TextButton(
|
||||
onPressed: followLink,
|
||||
child: const Text('View author (Link)'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -46,18 +46,9 @@ class _BooksScreenState extends State<BooksScreen>
|
||||
bottom: TabBar(
|
||||
controller: _tabController,
|
||||
tabs: const [
|
||||
Tab(
|
||||
text: 'Popular',
|
||||
icon: Icon(Icons.people),
|
||||
),
|
||||
Tab(
|
||||
text: 'New',
|
||||
icon: Icon(Icons.new_releases),
|
||||
),
|
||||
Tab(
|
||||
text: 'All',
|
||||
icon: Icon(Icons.list),
|
||||
),
|
||||
Tab(text: 'Popular', icon: Icon(Icons.people)),
|
||||
Tab(text: 'New', icon: Icon(Icons.new_releases)),
|
||||
Tab(text: 'All', icon: Icon(Icons.list)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -30,18 +30,9 @@ class BookstoreScaffold extends StatelessWidget {
|
||||
if (idx == 2) goRouter.go('/settings');
|
||||
},
|
||||
destinations: const [
|
||||
AdaptiveScaffoldDestination(
|
||||
title: 'Books',
|
||||
icon: Icons.book,
|
||||
),
|
||||
AdaptiveScaffoldDestination(
|
||||
title: 'Authors',
|
||||
icon: Icons.person,
|
||||
),
|
||||
AdaptiveScaffoldDestination(
|
||||
title: 'Settings',
|
||||
icon: Icons.settings,
|
||||
),
|
||||
AdaptiveScaffoldDestination(title: 'Books', icon: Icons.book),
|
||||
AdaptiveScaffoldDestination(title: 'Authors', icon: Icons.person),
|
||||
AdaptiveScaffoldDestination(title: 'Settings', icon: Icons.settings),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -18,81 +18,79 @@ class SettingsScreen extends StatefulWidget {
|
||||
class _SettingsScreenState extends State<SettingsScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 400),
|
||||
child: const Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 18, horizontal: 12),
|
||||
child: SettingsContent(),
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 400),
|
||||
child: const Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 18, horizontal: 12),
|
||||
child: SettingsContent(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class SettingsContent extends StatelessWidget {
|
||||
const SettingsContent({
|
||||
super.key,
|
||||
});
|
||||
const SettingsContent({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Column(
|
||||
children: [
|
||||
...[
|
||||
Text(
|
||||
'Settings',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
BookstoreAuth.of(context).signOut();
|
||||
},
|
||||
child: const Text('Sign out'),
|
||||
),
|
||||
const Text('Example using the Link widget:'),
|
||||
Link(
|
||||
uri: Uri.parse('/books/all/book/0'),
|
||||
builder: (context, followLink) => TextButton(
|
||||
children: [
|
||||
...[
|
||||
Text('Settings', style: Theme.of(context).textTheme.headlineMedium),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
BookstoreAuth.of(context).signOut();
|
||||
},
|
||||
child: const Text('Sign out'),
|
||||
),
|
||||
const Text('Example using the Link widget:'),
|
||||
Link(
|
||||
uri: Uri.parse('/books/all/book/0'),
|
||||
builder:
|
||||
(context, followLink) => TextButton(
|
||||
onPressed: followLink,
|
||||
child: const Text('/books/all/book/0'),
|
||||
),
|
||||
),
|
||||
const Text('Example using GoRouter.of(context).go():'),
|
||||
TextButton(
|
||||
child: const Text('/books/all/book/0'),
|
||||
onPressed: () {
|
||||
GoRouter.of(context).go('/books/all/book/0');
|
||||
},
|
||||
),
|
||||
].map((w) => Padding(padding: const EdgeInsets.all(8), child: w)),
|
||||
const Text('Displays a dialog on the root Navigator:'),
|
||||
TextButton(
|
||||
onPressed: () => showDialog<String>(
|
||||
),
|
||||
const Text('Example using GoRouter.of(context).go():'),
|
||||
TextButton(
|
||||
child: const Text('/books/all/book/0'),
|
||||
onPressed: () {
|
||||
GoRouter.of(context).go('/books/all/book/0');
|
||||
},
|
||||
),
|
||||
].map((w) => Padding(padding: const EdgeInsets.all(8), child: w)),
|
||||
const Text('Displays a dialog on the root Navigator:'),
|
||||
TextButton(
|
||||
onPressed:
|
||||
() => showDialog<String>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Alert!'),
|
||||
content: const Text('The alert description goes here.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, 'Cancel'),
|
||||
child: const Text('Cancel'),
|
||||
builder:
|
||||
(context) => AlertDialog(
|
||||
title: const Text('Alert!'),
|
||||
content: const Text('The alert description goes here.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, 'Cancel'),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, 'OK'),
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, 'OK'),
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: const Text('Show Dialog'),
|
||||
)
|
||||
],
|
||||
);
|
||||
child: const Text('Show Dialog'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,10 +14,7 @@ class Credentials {
|
||||
class SignInScreen extends StatefulWidget {
|
||||
final ValueChanged<Credentials> onSignIn;
|
||||
|
||||
const SignInScreen({
|
||||
required this.onSignIn,
|
||||
super.key,
|
||||
});
|
||||
const SignInScreen({required this.onSignIn, super.key});
|
||||
|
||||
@override
|
||||
State<SignInScreen> createState() => _SignInScreenState();
|
||||
@@ -29,41 +26,46 @@ class _SignInScreenState extends State<SignInScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
body: Center(
|
||||
child: Card(
|
||||
child: Container(
|
||||
constraints: BoxConstraints.loose(const Size(600, 600)),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('Sign in',
|
||||
style: Theme.of(context).textTheme.headlineMedium),
|
||||
TextField(
|
||||
decoration: const InputDecoration(labelText: 'Username'),
|
||||
controller: _usernameController,
|
||||
),
|
||||
TextField(
|
||||
decoration: const InputDecoration(labelText: 'Password'),
|
||||
obscureText: true,
|
||||
controller: _passwordController,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
widget.onSignIn(Credentials(
|
||||
_usernameController.value.text,
|
||||
_passwordController.value.text));
|
||||
},
|
||||
child: const Text('Sign in'),
|
||||
),
|
||||
),
|
||||
],
|
||||
body: Center(
|
||||
child: Card(
|
||||
child: Container(
|
||||
constraints: BoxConstraints.loose(const Size(600, 600)),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Sign in',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
decoration: const InputDecoration(labelText: 'Username'),
|
||||
controller: _usernameController,
|
||||
),
|
||||
TextField(
|
||||
decoration: const InputDecoration(labelText: 'Password'),
|
||||
obscureText: true,
|
||||
controller: _passwordController,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
widget.onSignIn(
|
||||
Credentials(
|
||||
_usernameController.value.text,
|
||||
_passwordController.value.text,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('Sign in'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,23 +10,16 @@ class AuthorList extends StatelessWidget {
|
||||
final List<Author> authors;
|
||||
final ValueChanged<Author>? onTap;
|
||||
|
||||
const AuthorList({
|
||||
required this.authors,
|
||||
this.onTap,
|
||||
super.key,
|
||||
});
|
||||
const AuthorList({required this.authors, this.onTap, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView.builder(
|
||||
itemCount: authors.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
title: Text(
|
||||
authors[index].name,
|
||||
),
|
||||
subtitle: Text(
|
||||
'${authors[index].books.length} books',
|
||||
),
|
||||
itemCount: authors.length,
|
||||
itemBuilder:
|
||||
(context, index) => ListTile(
|
||||
title: Text(authors[index].name),
|
||||
subtitle: Text('${authors[index].books.length} books'),
|
||||
onTap: onTap != null ? () => onTap!(authors[index]) : null,
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,23 +10,16 @@ class BookList extends StatelessWidget {
|
||||
final List<Book> books;
|
||||
final ValueChanged<Book>? onTap;
|
||||
|
||||
const BookList({
|
||||
required this.books,
|
||||
this.onTap,
|
||||
super.key,
|
||||
});
|
||||
const BookList({required this.books, this.onTap, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView.builder(
|
||||
itemCount: books.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
title: Text(
|
||||
books[index].title,
|
||||
),
|
||||
subtitle: Text(
|
||||
books[index].author.name,
|
||||
),
|
||||
itemCount: books.length,
|
||||
itemBuilder:
|
||||
(context, index) => ListTile(
|
||||
title: Text(books[index].title),
|
||||
subtitle: Text(books[index].author.name),
|
||||
onTap: onTap != null ? () => onTap!(books[index]) : null,
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@@ -37,8 +37,11 @@ class PageBasedFadeTransitionRoute<T> extends PageRoute<T> {
|
||||
bool get maintainState => true;
|
||||
|
||||
@override
|
||||
Widget buildPage(BuildContext context, Animation<double> animation,
|
||||
Animation<double> secondaryAnimation) {
|
||||
Widget buildPage(
|
||||
BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
) {
|
||||
var curveTween = CurveTween(curve: Curves.easeIn);
|
||||
return FadeTransition(
|
||||
opacity: animation.drive(curveTween),
|
||||
@@ -47,7 +50,10 @@ class PageBasedFadeTransitionRoute<T> extends PageRoute<T> {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildTransitions(BuildContext context, Animation<double> animation,
|
||||
Animation<double> secondaryAnimation, Widget child) =>
|
||||
child;
|
||||
Widget buildTransitions(
|
||||
BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
Widget child,
|
||||
) => child;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user