@@ -10,31 +10,27 @@ import 'package:flutter/material.dart';
10
10
import 'package:http/http.dart' ;
11
11
import 'package:http/io_client.dart' ;
12
12
13
+ import 'book.dart' ;
14
+
13
15
void main () {
14
16
late Client client;
15
- if (Platform .isIOS) {
17
+ // Use Cupertino Http on iOS and macOS.
18
+ if (Platform .isIOS || Platform .isMacOS) {
16
19
client = CupertinoClient .defaultSessionConfiguration ();
17
20
} else {
18
21
client = IOClient ();
19
22
}
20
23
24
+ // Run the app with the default `client` set to the one assigned above.
21
25
runWithClient (() => runApp (const BookSearchApp ()), () => client);
22
26
}
23
27
24
- class Book {
25
- String title;
26
- String description;
27
- String imageUrl;
28
-
29
- Book (this .title, this .description, this .imageUrl);
30
- }
31
-
32
28
class BookSearchApp extends StatelessWidget {
33
29
const BookSearchApp ({Key ? key}) : super (key: key);
34
30
35
31
@override
36
32
Widget build (BuildContext context) => const MaterialApp (
37
- // Remove the debug banner
33
+ // Remove the debug banner.
38
34
debugShowCheckedModeBanner: false ,
39
35
title: 'Book Search' ,
40
36
home: HomePage (),
@@ -49,88 +45,71 @@ class HomePage extends StatefulWidget {
49
45
}
50
46
51
47
class _HomePageState extends State <HomePage > {
52
- List <Book > _books = [] ;
48
+ List <Book >? _books;
53
49
54
50
@override
55
51
void initState () {
56
52
super .initState ();
57
53
}
58
54
59
- void _runSearch (String query) {
55
+ // Get the list of books matching `query`.
56
+ // The `get` call will automatically use the `client` configurated in `main`.
57
+ Future <List <Book >> _getBooks (String query) async {
58
+ final response = await get (
59
+ Uri .https (
60
+ 'www.googleapis.com' ,
61
+ '/books/v1/volumes' ,
62
+ {'q' : query, 'maxResults' : '40' , 'printType' : 'books' },
63
+ ),
64
+ );
65
+
66
+ final json = jsonDecode (utf8.decode (response.bodyBytes)) as Map ;
67
+ return Book .listFromJson (json);
68
+ }
69
+
70
+ void _runSearch (String query) async {
60
71
if (query.isEmpty) {
61
72
setState (() {
62
- _books = [] ;
73
+ _books = null ;
63
74
});
64
75
return ;
65
76
}
66
77
67
- // `get` will use the `Client` configured in main.
68
- get (Uri .https ('www.googleapis.com' , '/books/v1/volumes' , {
69
- 'q' : query,
70
- 'maxResults' : '40' ,
71
- 'printType' : 'books'
72
- })).then ((response) {
73
- final books = < Book > [];
74
- final jsonPayload = jsonDecode (utf8.decode (response.bodyBytes)) as Map ;
75
-
76
- if (jsonPayload['items' ] is List <dynamic >) {
77
- final items =
78
- (jsonPayload['items' ] as List ).cast <Map <String , Object ?>>();
79
-
80
- for (final item in items) {
81
- if (item.containsKey ('volumeInfo' )) {
82
- final volumeInfo = item['volumeInfo' ] as Map ;
83
- if (volumeInfo['title' ] is String &&
84
- volumeInfo['description' ] is String &&
85
- volumeInfo['imageLinks' ] is Map &&
86
- (volumeInfo['imageLinks' ] as Map )['smallThumbnail' ] is String ) {
87
- books.add (Book (
88
- volumeInfo['title' ] as String ,
89
- volumeInfo['description' ] as String ,
90
- (volumeInfo['imageLinks' ] as Map )['smallThumbnail' ]
91
- as String ));
92
- }
93
- }
94
- }
95
- }
96
- setState (() {
97
- _books = books;
98
- });
78
+ final books = await _getBooks (query);
79
+ setState (() {
80
+ _books = books;
99
81
});
100
82
}
101
83
102
84
@override
103
- Widget build (BuildContext context) => Scaffold (
104
- appBar: AppBar (
105
- title: const Text ('Book Search' ),
106
- ),
107
- body: Padding (
108
- padding: const EdgeInsets .all (10 ),
109
- child: Column (
110
- children: [
111
- const SizedBox (
112
- height: 20 ,
113
- ),
114
- TextField (
115
- onChanged: _runSearch,
116
- decoration: const InputDecoration (
117
- labelText: 'Search' , suffixIcon: Icon (Icons .search)),
118
- ),
119
- const SizedBox (
120
- height: 20 ,
121
- ),
122
- Expanded (
123
- child: _books.isNotEmpty
124
- ? BookList (_books)
125
- : const Text (
126
- 'No results found' ,
127
- style: TextStyle (fontSize: 24 ),
128
- ),
85
+ Widget build (BuildContext context) {
86
+ final searchResult = _books == null
87
+ ? const Text ('Please enter a query' , style: TextStyle (fontSize: 24 ))
88
+ : _books! .isNotEmpty
89
+ ? BookList (_books! )
90
+ : const Text ('No results found' , style: TextStyle (fontSize: 24 ));
91
+
92
+ return Scaffold (
93
+ appBar: AppBar (title: const Text ('Book Search' )),
94
+ body: Padding (
95
+ padding: const EdgeInsets .all (10 ),
96
+ child: Column (
97
+ children: [
98
+ const SizedBox (height: 20 ),
99
+ TextField (
100
+ onChanged: _runSearch,
101
+ decoration: const InputDecoration (
102
+ labelText: 'Search' ,
103
+ suffixIcon: Icon (Icons .search),
129
104
),
130
- ],
131
- ),
105
+ ),
106
+ const SizedBox (height: 20 ),
107
+ Expanded (child: searchResult),
108
+ ],
132
109
),
133
- );
110
+ ),
111
+ );
112
+ }
134
113
}
135
114
136
115
class BookList extends StatefulWidget {
0 commit comments