Code Daftar Buku Refresh Widget

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({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),

                  ),

                ],

              ),

            ),

          ],

        ),

      ),

    );

  }

}


Previous Post Next Post