import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(
ChangeNotifierProvider<ThemeModeNotifier>(
create: (_) => ThemeModeNotifier(),
child: MyBooks(),
),
);
}
class ThemeModeNotifier extends ChangeNotifier {
ThemeMode _themeMode = ThemeMode.system;
ThemeMode get themeMode => _themeMode;
set themeMode(ThemeMode mode) {
_themeMode = mode;
notifyListeners();
}
}
class MyBooks extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<ThemeModeNotifier>(
builder: (context, themeModeNotifier, child) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Daftar Buku API',
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: themeModeNotifier.themeMode,
home: BookListScreen(),
);
},
);
}
}
class Book {
final String title;
final String subtitle;
final String image;
final String url;
String authors;
String publisher;
String language;
String isbn10;
String isbn13;
String pages;
String year;
String rating;
String desc;
String price;
bool isDownloaded;
Book({
required this.title,
required this.subtitle,
required this.image,
required this.url,
required this.authors,
required this.publisher,
required this.language,
required this.isbn10,
required this.isbn13,
required this.pages,
required this.year,
required this.rating,
required this.desc,
required this.price,
required this.isDownloaded,
});
}
class BookListScreen extends StatefulWidget {
@override
_BookListScreenState createState() => _BookListScreenState();
}
class _BookListScreenState extends State<BookListScreen> {
List<Book> books = [];
List<Book> filteredBooks = [];
bool isDataLoaded = false;
@override
void initState() {
super.initState();
fetchBooks();
setDownloadStatus();
}
Future<void> fetchBooks({bool refresh = false}) async {
final response = await http.get(
Uri.parse('https://api.itbook.store/1.0/search/Flutter%20Developer'));
if (response.statusCode == 200) {
final jsonData = json.decode(response.body);
print(response.body);
setState(() {
final bookList = jsonData['books'] as List<dynamic>;
if (refresh) {
books = bookList
.map((bookData) => Book(
title: bookData['title'],
subtitle: bookData['subtitle'],
image: bookData['image'],
url: bookData['url'],
authors: '',
publisher: '',
language: '',
isbn10: '',
isbn13: '',
pages: '',
year: '',
rating: '',
desc: '',
price: '',
isDownloaded: false,
))
.toList();
} else {
books.addAll(bookList
.map((bookData) => Book(
title: bookData['title'],
subtitle: bookData['subtitle'],
image: bookData['image'],
url: bookData['url'],
authors: '',
publisher: '',
language: '',
isbn10: '',
isbn13: '',
pages: '',
year: '',
rating: '',
desc: '',
price: '',
isDownloaded: false,
))
.toList());
}
filteredBooks = books;
isDataLoaded = true;
});
}
}
void setDownloadStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
for (var book in books) {
bool isDownloaded = prefs.getBool(book.title) ?? false;
book.isDownloaded = isDownloaded;
}
});
}
void toggleDownloadStatus(Book book) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isDownloaded = prefs.getBool(book.title) ?? false;
setState(() {
book.isDownloaded = !isDownloaded;
});
await prefs.setBool(book.title, !isDownloaded);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Daftar Buku'),
),
body: isDataLoaded
? RefreshIndicator(
onRefresh: () => fetchBooks(refresh: true),
child: ListView.builder(
itemCount: filteredBooks.length,
itemBuilder: (context, index) {
final book = filteredBooks[index];
return ListTile(
leading: CachedNetworkImage(
imageUrl: book.image,
placeholder: (context, url) =>
CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
title: Text(book.title),
subtitle: Text(book.subtitle),
trailing: IconButton(
icon: book.isDownloaded
? Icon(Icons.download_done)
: Icon(Icons.download),
onPressed: () => toggleDownloadStatus(book),
),
onTap: () {
fetchBookDetails(book);
},
);
},
),
)
: Center(
child: CircularProgressIndicator(),
),
);
}
Future<void> fetchBookDetails(Book book) async {
final response = await http.get(Uri.parse(book.url));
if (response.statusCode == 200) {
final jsonData = json.decode(response.body);
setState(() {
book.authors = jsonData['authors'];
book.publisher = jsonData['publisher'];
book.language = jsonData['language'];
book.isbn10 = jsonData['isbn10'];
book.isbn13 = jsonData['isbn13'];
book.pages = jsonData['pages'];
book.year = jsonData['year'];
book.rating = jsonData['rating'];
book.desc = jsonData['desc'];
book.price = jsonData['price'];
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BookDetailScreen(book: book),
),
);
}
}
}
class BookDetailScreen extends StatelessWidget {
final Book book;
BookDetailScreen({required this.book});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(book.title),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (book.image.isNotEmpty)
Center(
child: CachedNetworkImage(
imageUrl: book.image,
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Title: ${book.title}',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text(
'Subtitle: ${book.subtitle}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'Authors: ${book.authors}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'Publisher: ${book.publisher}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'Language: ${book.language}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'ISBN-10: ${book.isbn10}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'ISBN-13: ${book.isbn13}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'Pages: ${book.pages}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'Year: ${book.year}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'Rating: ${book.rating}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'Description: ${book.desc}',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
Text(
'Price: ${book.price}',
style: TextStyle(fontSize: 16),
),
],
),
),
],
),
),
);
}
}