open_library
A Flutter implementation of openlibrary.org api.
Features
- fetch book information using the https://openlibrary.org api ISBN
- supports 10 and 13 digit ISBN numbers
- adds authors and covers to the book result object
- covers can be easily used in flutter providing MemoryImages using Uint8List as covers
- search for books using the query methods for title, authors, isbn and unified queries
- new search patterns for subject, place, person, language, and publisher
- load covers in small, medium, large or even disable cover load
Example App
Install
In the pubspec.yaml
of your flutter project, add the following dependency:
dependencies:
open_library: <latest_version>
In your library add the following import:
import 'package:open_library/open_library.dart';
Getting started
Example:
import 'package:flutter/material.dart';
import 'package:open_library/open_library.dart';
import 'package:provider/provider.dart';
import 'screens/book_screen.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Provider(
create: (_) => OpenLibrary(),
dispose: (_, OpenLibrary service) => service.dispose(),
child: MaterialApp(
title: 'Book Example',
home: BookScreen()
));
}
}
import 'package:flutter/material.dart';
import 'package:open_library/models/ol_book_model.dart';
import 'package:open_library/models/ol_search_model.dart';
import 'package:open_library/open_library.dart';
import 'package:provider/provider.dart';
const ISBN1 = '9783608980806';
const ISBN2 = '0674995171';
const ISBN3 = '3596191130';
class BookScreen extends StatefulWidget {
BookScreen({Key? key}) : super(key: key);
final List<OLBook> books = [];
@override
State<BookScreen> createState() => _BookScreenState();
}
class _BookScreenState extends State<BookScreen> {
final TextEditingController controller =
TextEditingController(text: "Lord of the Rings");
late bool isLoading = false;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueGrey,
body: !isLoading
? Column(
children: [
const SizedBox(height: 50.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.6,
height: 60.0,
child: TextField(
controller: controller,
cursorColor: Colors.white,
style: const TextStyle(color: Colors.white),
decoration: const InputDecoration(
label: Text("Book title:"),
labelStyle: TextStyle(color: Colors.white),
focusColor: Colors.white,
),
),
),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: GestureDetector(
onTap: () async {
setState(() {
isLoading = true;
});
final OLSearchBase search =
await Provider.of<OpenLibrary>(context,
listen: false)
.query(q: controller.text, limit: 4);
if (search is OLSearch) {
widget.books.clear();
print("search:\n$search");
for (var doc in search.docs) {
final OLBook book = OLBook(
title: doc.title,
authors: doc.authors,
covers: doc.covers,
);
widget.books.add(book);
}
}
setState(() {
isLoading = false;
});
},
child: const Icon(
Icons.search,
color: Colors.white,
),
),
),
],
),
const SizedBox(
height: 20.0,
),
const Center(
child: Text(
"press action button to search for those ISBN's",
style: TextStyle(color: Colors.white),
)),
const SizedBox(
height: 20.0,
),
const Center(
child: Text(
"ISBN1:$ISBN1",
style: TextStyle(color: Colors.white),
)),
const SizedBox(height: 20.0),
const Center(
child: Text(
"ISBN2:$ISBN2",
style: TextStyle(color: Colors.white),
)),
const SizedBox(height: 20.0),
const Center(
child: Text(
"ISBN3:$ISBN3",
style: TextStyle(color: Colors.white),
)),
const SizedBox(height: 20.0),
SingleChildScrollView(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.books.length,
itemBuilder: (context, index) {
return bookWidget(
book: widget.books[index], context: context);
},
),
)
],
)
: const Center(child: CircularProgressIndicator(color: Colors.white,)),
floatingActionButton: FloatingActionButton(
onPressed: () async {
setState(() {
isLoading = true;
});
widget.books.clear();
const bool loadCovers = true;
const CoverSize size = CoverSize.S;
final OLBookBase book1 =
await Provider.of<OpenLibrary>(context, listen: false)
.getBookByISBN(
isbn: ISBN1, loadCover: loadCovers, coverSize: size);
print(book1.toString());
if (book1 is OLBook) {
widget.books.add(book1);
}
final OLBookBase book2 =
await Provider.of<OpenLibrary>(context, listen: false)
.getBookByISBN(
isbn: ISBN2, loadCover: loadCovers, coverSize: size);
print(book2.toString());
if (book2 is OLBook) {
widget.books.add(book2);
}
final OLBookBase book3 =
await Provider.of<OpenLibrary>(context, listen: false)
.getBookByISBN(
isbn: ISBN3, loadCover: loadCovers, coverSize: size);
print(book3.toString());
if (book3 is OLBook) {
widget.books.add(book3);
}
setState(() {
isLoading = false;
});
},
child: const Icon(Icons.book),
),
);
}
Widget bookWidget({required OLBook book, required BuildContext context}) {
String author = '';
if (book.authors.isNotEmpty) {
author = book.authors.first.name.trim();
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
height: 80.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding:
const EdgeInsets.only(top: 4.0, bottom: 4.0, left: 20.0),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.6,
child: Text(
book.title,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.bold),
),
),
),
Padding(
padding:
const EdgeInsets.only(top: 4.0, bottom: 4.0, left: 20.0),
child: Text(
author,
style: const TextStyle(color: Colors.black, fontSize: 12),
),
),
],
),
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: SizedBox(
height: book.covers.isNotEmpty ? 64.0 : 0,
child: book.covers.isNotEmpty
? Image.memory(book.covers.first)
: null,
),
),
],
),
),
);
}
}