Code Flutter Daftar Buku API menampilkan icon download

Konten [Tampil]

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() 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>;


        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();


        filteredBooks = books;

      });


      // Menampilkan data setiap detail buku

      for (final book in books) {

        await fetchBookDetails(book);

      }

    } else {

      throw Exception('Gagal');

    }

  }


  Future<void> fetchBookDetails(Book book) async {

    final response = await http

        .get(Uri.parse('https://api.itbook.store/1.0/books/9781484206485'));


    if (response.statusCode == 200) {

      final jsonData = json.decode(response.body);

      print(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'];


        filteredBooks = books;

        isDataLoaded = true;

      });

    } else {

      setState(() {

        isDataLoaded = false;

      });

      throw Exception('Gagal mengambil data');

    }

  }


  void setDownloadStatus() async {

    SharedPreferences prefs = await SharedPreferences.getInstance();

    List<String>? downloadedBooks = prefs.getStringList('downloaded_books');


    if (downloadedBooks != null) {

      for (final book in books) {

        if (downloadedBooks.contains(book.title)) {

          setState(() {

            book.isDownloaded = true;

          });

        }

      }

    }

  }


  void toggleDownloadStatus(Book book) async {

    SharedPreferences prefs = await SharedPreferences.getInstance();

    List<String>? downloadedBooks = prefs.getStringList('downloaded_books');


    if (downloadedBooks == null) {

      downloadedBooks = [];

    }


    setState(() {

      if (book.isDownloaded) {

        book.isDownloaded = false;

        downloadedBooks?.remove(book.title);

      } else {

        book.isDownloaded = true;

        downloadedBooks?.add(book.title);

      }

    });


    prefs.setStringList('downloaded_books', downloadedBooks);

  }


  void filterBooks(String query) {

    setState(() {

      if (query.isEmpty) {

        filteredBooks = books;

      } else {

        filteredBooks = books

            .where((book) =>

                book.title.toLowerCase().contains(query.toLowerCase()) ||

                book.subtitle.toLowerCase().contains(query.toLowerCase()))

            .toList();

      }

    });

  }


  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(

        title: Text('Daftar Buku dari API'),

        actions: [

          IconButton(

            icon: Icon(Icons.search),

            onPressed: () async {

              final Book? selectedBook = await showSearch(

                context: context,

                delegate: BookSearchDelegate(books),

              );


              if (selectedBook != null) {

                Navigator.push(

                  context,

                  MaterialPageRoute(

                    builder: (context) => BookDetailScreen(

                      book: selectedBook,

                      themeModeNotifier: context.read<ThemeModeNotifier>(),

                    ),

                  ),

                );

              }

            },

          ),

        ],

      ),

      body: isDataLoaded

          ? ListView.builder(

              itemCount: filteredBooks.length,

              itemBuilder: (context, index) {

                final book = filteredBooks[index];

                return Card(

                  child: 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: Icon(

                        book.isDownloaded ? Icons.check : Icons.download,

                      ),

                      onPressed: () {

                        toggleDownloadStatus(book);

                      },

                    ),

                    onTap: () {

                      Navigator.push(

                        context,

                        MaterialPageRoute(

                          builder: (context) => BookDetailScreen(

                            book: book,

                            themeModeNotifier: context.read<ThemeModeNotifier>(),

                          ),

                        ),

                      );

                    },

                  ),

                );

              },

            )

          : Center(

              child: CircularProgressIndicator(),

            ),

    );

  }

}


class BookSearchDelegate extends SearchDelegate<Book> {

  final List<Book> books;


  BookSearchDelegate(this.books);


  @override

  List<Widget> buildActions(BuildContext context) {

    return [

      IconButton(

        icon: Icon(Icons.clear),

        onPressed: () {

          query = '';

        },

      ),

    ];

  }


  @override

  Widget buildLeading(BuildContext context) {

    return IconButton(

      icon: Icon(Icons.arrow_back),

      onPressed: () {

        close(context, null!);

      },

    );

  }


  @override

  Widget buildResults(BuildContext context) {

    final filteredBooks = books

        .where((book) =>

            book.title.toLowerCase().contains(query.toLowerCase()) ||

            book.subtitle.toLowerCase().contains(query.toLowerCase()))

        .toList();


    return ListView.builder(

      itemCount: filteredBooks.length,

      itemBuilder: (context, index) {

        final book = filteredBooks[index];

        return ListTile(

          title: Text(book.title),

          subtitle: Text(book.subtitle),

          onTap: () {

            close(context, book);

          },

        );

      },

    );

  }


  @override

  Widget buildSuggestions(BuildContext context) {

    final filteredBooks = books

        .where((book) =>

            book.title.toLowerCase().contains(query.toLowerCase()) ||

            book.subtitle.toLowerCase().contains(query.toLowerCase()))

        .toList();


    return ListView.builder(

      itemCount: filteredBooks.length,

      itemBuilder: (context, index) {

        final book = filteredBooks[index];

        return ListTile(

          title: Text(book.title),

          subtitle: Text(book.subtitle),

          onTap: () {

            query = book.title;

            close(context, book);

          },

        );

      },

    );

  }

}


class BookDetailScreen extends StatelessWidget {

  final Book book;

  final ThemeModeNotifier themeModeNotifier;


  BookDetailScreen({

    required this.book,

    required this.themeModeNotifier,

  });


  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(

        title: Text('Detail Buku'),

        actions: [

          IconButton(

            icon: Icon(

              themeModeNotifier.themeMode == ThemeMode.light

                  ? Icons.lightbulb_outline

                  : Icons.lightbulb,

            ),

            onPressed: () {

              final newThemeMode = themeModeNotifier.themeMode == ThemeMode.light

                  ? ThemeMode.dark

                  : ThemeMode.light;

              themeModeNotifier.themeMode = newThemeMode;

            },

          ),

        ],

      ),

      body: ListView(

        children: [

          CachedNetworkImage(

            imageUrl: book.image,

            placeholder: (context, url) => CircularProgressIndicator(),

            errorWidget: (context, url, error) => Icon(Icons.error),

          ),

          ListTile(

            title: Text(book.title),

            subtitle: Text(book.subtitle),

          ),

          ListTile(

            title: Text('Authors'),

            subtitle: Text(book.authors),

          ),

          ListTile(

            title: Text('Publisher'),

            subtitle: Text(book.publisher),

          ),

          ListTile(

            title: Text('Language'),

            subtitle: Text(book.language),

          ),

          ListTile(

            title: Text('ISBN-10'),

            subtitle: Text(book.isbn10),

          ),

          ListTile(

            title: Text('ISBN-13'),

            subtitle: Text(book.isbn13),

          ),

          ListTile(

            title: Text('Pages'),

            subtitle: Text(book.pages),

          ),

          ListTile(

            title: Text('Year'),

            subtitle: Text(book.year),

          ),

          ListTile(

            title: Text('Rating'),

            subtitle: Text(book.rating),

          ),

          ListTile(

            title: Text('Description'),

            subtitle: Text(book.desc),

          ),

          ListTile(

            title: Text('Price'),

            subtitle: Text(book.price),

          ),

        ],

      ),

    );

  }

}


Previous Post Next Post