3Flutter Beginner Project - Ebook application

Last updated Sep 29, 2021


This is an EBook flutter application where you can show all types of books in one place to readers. This will show Book list, Book details like Book Name, Author name, Price, Free or Paid. If the Free book it will load the PDF inside application then readers can read the book.

This Application developed with Flutter as Frontend and PHP as Backend.

Flutter app contains below screens

  • Home Screen : Display the few books as Category wise
  • Search Screen: Where book reader can search book by its name, author name or book description
  • Book List: Where Reader can see all books related to selected category
  • Book Details: Where reader can see complete book details like price (free/paid), book description, author name, and finally user can buy a book by tap on Buy button (If Paid Book) or Can read by tap on Read (If Free book).

PHP :  This project contains below files as created with Core PHP

  • bookbycat.php
  • bookdetails.php
  • booksearch.php
  • categories.php
  • db_config.php
  • db_connect.php

 

App Architecture

Flutter Ebook Application

 

Download app from playstore

 

This project we build with Bloc pattern with cubit to maintain the state of the application.

Step 1: Create Flutter application with your favorite IDE, here we used Android studio.

Step 2: App communicates with backend, so let's creat a class to add your api end points

This class under core/apis folder

class ApiConstants{
  ApiConstants._();
  static const String base = "BASE_URL";
  static const String book_list = "bookbycat";
  static const String book_details = "bookdetails";
  static const String book_category = "categories";
  static const String book_search = "booksearch";
}

 

Step 3: To communicate with server we need to add network libraries to our application, in this we used

  • Dio network library
  • Block pattern to state management
  • flutter_html to load html inside application
  • connectivity_plus to handle network connectivity

 

Lets add required dependencies to pubspec.yaml file

dependencies:
  flutter:
    sdk: flutter
  google_fonts: ^2.1.0
  dio: ^4.0.0
  flutter_bloc: ^7.1.0
  url_launcher: ^6.0.10
  flutter_html: ^2.0.0
  connectivity_plus: ^1.1.0
  flutter_svg: ^0.22.0

 

Step 3: Let's create ClientRequest class to manage network call

This class under core/apis folder

import 'package:aone/core/apis/constants.dart';
import 'package:dio/dio.dart';

import 'fake_data.dart';

class ClientRequest{
  late final Dio dio;
  ClientRequest(this.dio);
  get(String path,String? token, Map?query,bool fake) async{

    if(fake)
      {

        return getFakeData(path);
      }

    dynamic response;

    response=await dio.get(ApiConstants.base+path+".php",
        queryParameters: query,
        options: Options(
          method: 'GET',
          headers: token != null ? {'Authorization': token} : null,
        ));

    if (response?.statusCode == 200) {

      return response.data;
    } else if (response?.statusCode == 401) {

      throw Exception("UnAuthorized");
    } else {

      throw Exception(response.statusMessage);
    }
  }
}

 

In the above class we were created a fake data call if we doesn't want to get data from server.

fake.dart file should be like below. This class under core/apis folder

 import 'package:aone/core/apis/constants.dart';

dynamic getFakeData(String path){

  switch(path)
  {

   case ApiConstants.book_list: return getBookList();
   case ApiConstants.book_category: return getCategory();
   case ApiConstants.book_search: return getBookList();
  }
}

getBookList(){

 return {"result": [
  {
   "id":"1",
   "title":"BookTitle1",
   "author":"Author Name",
   "is_paid":1,
   "price":200,
   "img":"",
   "thumb_nail":"",
   "details":"Book Details",
   "source":"",
   "download_path":"",
   "category_id":1,
   "catebory_name":"category name"
  },
  {
   "id":"2",
   "title":"BookTitle2",
   "author":"Author Name",
   "is_paid":1,
   "price":200,
   "img":"",
   "thumb_nail":"",
   "details":"Book Details",
   "source":"",
   "download_path":"",
   "category_id":1,
   "catebory_name":"category name"
  },
  {
   "id":"3",
   "title":"BookTitle3",
   "author":"Author Name",
   "is_paid":0,
   "price":200,
   "img":"",
   "thumb_nail":"",
   "details":"Book Details",
   "source":"",
   "download_path":"",
   "category_id":2,
   "catebory_name":"category name"
  },
  {
   "id":"3",
   "title":"BookTitle3",
   "author":"Author Name",
   "is_paid":0,
   "price":200,
   "img":"",
   "thumb_nail":"",
   "details":"Book Details",
   "source":"",
   "download_path":"",
   "category_id":2,
   "catebory_name":"category name"
  },
  {
   "id":"3",
   "title":"BookTitle3",
   "author":"Author Name",
   "is_paid":0,
   "price":200,
   "img":"",
   "thumb_nail":"",
   "details":"Book Details",
   "source":"",
   "download_path":"",
   "category_id":2,
   "catebory_name":"category name"
  }
 ]};
}

getCategory(){

 return {"category":[
  {"id":"1","name":"IT Books"},
  {"id":"2","name":"Fun"},
  {"id":"3","name":"CBSE"},
  {"id":"4","name":"Quotation"},
  {"id":"5","name":"Quotation"},
 ]};
 }

 

Step 4: Now lets create route_page,settings page app_theme and custom_appbar pages. These files under core folder

route_page.dart

import 'package:aone/presentation/journey/screens/book_details.dart';
import 'package:aone/presentation/journey/screens/book_list.dart';
import 'package:aone/presentation/journey/screens/error_page.dart';
import 'package:aone/presentation/journey/screens/filter_books.dart';
import 'package:aone/presentation/journey/screens/homepage.dart';
import 'package:flutter/material.dart';

final GlobalKey rootNavKey = GlobalKey();
class RouteGenerator {
  static RoutegenerateRoute(RouteSettings settings){
    final dynamic args = settings.arguments;
    switch(settings.name)
    {
      case AppRoutes.landing:  return MaterialPageRoute(builder: (_)=>HomePage());

      case AppRoutes.booklist:  return MaterialPageRoute(builder: (_)=>BookList(args));
      case AppRoutes.bookdetails:  return MaterialPageRoute(builder: (_)=>BookDetails(args));
      case AppRoutes.filter:  return MaterialPageRoute(builder: (_)=>FilterBook());
      case AppRoutes.error:  return MaterialPageRoute(builder: (_)=>ErrorPage(message: "No Network"));
      default:
        return _errorRoute(args);
    }

  }
  static _errorRoute(dynamic args) {
    return MaterialPageRoute(
      builder: (_) => ErrorPage(message: args),
    );
  }
}

class AppRoutes {
  static const String landing = '/';
  static const String error = '/error';
  static const String login = '/login';
  static const String signup = '/signup';
  static const String booklist = '/booklist';
  static const String bookdetails = '/bookdetails';
  static const String filter = '/filter';
}

 

settings page

class Strings{
    const Strings();
    static final  String app_name="AOne";
    static final  String search_books="Search Books...";
    static final  String enter_book_name="Enter a book name";
    static final  String see_all='More';
}

 

app_themes.dart

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class AppColor {
  const AppColor._();

  //darkColor
  static const Color darkUnselectedColor = Colors.white60;
  static const Color darkPrimary = Color(0xFF32CD32);
  static const Color darkAccent = Color(0xFF32CD32);
  static const Color darkBackgroundColor = Color(0xFF202020);
  static const Color darkCanvasColor = Colors.black;
  static const Color darkCardColor = Colors.black;
  static const Color darkBorderColor = Colors.white60;
  static const Color darkPrimaryTextColor = Colors.white;
  static const Color darkSecondaryTextColor = Colors.white70;

  //lightColor
  static const Color lightUnselectedColor = Colors.black54;
  static const Color lightPrimary = Color(0xFF32CD32);
  static const Color lightAccent = Color(0xFF32CD32);
  static const Color lightBackgroundColor = Color(0xFFF5F5F5);
  static const Color lightCanvasColor = Colors.white;
  static const Color lightCardColor = Colors.white;
  static const Color lightBorderColor = Colors.black54;
  static const Color lightPrimaryTextColor = Colors.black;
  static const Color lightSecondaryTextColor = Colors.black87;

  //button colors
  static const Color buttonColor = Color(0xFF32CD32);
  static const Color buttonTextColor = Colors.white;
  static const Color tagTextColor = Colors.black54;
}

class AppTheme {
  const AppTheme._();

  static ThemeData init(BuildContext context, Themes theme) {
    return ThemeData(
      unselectedWidgetColor: theme == Themes.dark
          ? AppColor.darkUnselectedColor
          : AppColor.lightUnselectedColor,
      primaryColor:
      theme == Themes.dark ? AppColor.darkPrimary : AppColor.lightPrimary,
      accentColor:
      theme == Themes.dark ? AppColor.darkAccent : AppColor.lightAccent,
      scaffoldBackgroundColor: theme == Themes.dark
          ? AppColor.darkBackgroundColor
          : AppColor.lightBackgroundColor,
      brightness: theme == Themes.dark ? Brightness.dark : Brightness.light,
      cardTheme: CardTheme(
        color: theme == Themes.dark
            ? AppColor.darkCardColor
            : AppColor.lightCardColor,
      ),
      dividerColor: theme == Themes.dark
          ? AppColor.darkBorderColor
          : AppColor.lightBorderColor,
      buttonColor: AppColor.buttonColor,
      visualDensity: VisualDensity.adaptivePlatformDensity,
      secondaryHeaderColor: theme == Themes.dark ? Colors.white : Colors.black,
      textTheme: theme == Themes.dark
          ? AppTheme.darkTextTheme()
          : AppTheme.lightTextTheme(),
      appBarTheme: AppBarTheme(
        elevation: 0,
        iconTheme: IconThemeData(
          color: theme == Themes.dark ? Colors.white : Colors.black,
        ),
        backgroundColor: theme == Themes.dark
            ? AppColor.darkCanvasColor
            : AppColor.lightCanvasColor,
        textTheme: theme == Themes.dark
            ? AppTheme.darkTextTheme()
            : AppTheme.lightTextTheme(),
      ),
      canvasColor: theme == Themes.dark
          ? AppColor.darkCanvasColor
          : AppColor.lightCanvasColor,
      inputDecorationTheme: InputDecorationTheme(
        border: InputBorder.none,
        hintStyle: theme == Themes.dark
            ? Theme.of(context).textTheme.darkHintStyle
            : Theme.of(context).textTheme.lightHintStyle,
      ),
    );
  }

  static TextTheme get _poppinsTextTheme => GoogleFonts.latoTextTheme();

  static TextStyle? get _headline6 => _poppinsTextTheme.headline6?.copyWith(
    fontSize: 20.0,
  );

  static TextStyle? get _headline5 => _poppinsTextTheme.headline5?.copyWith(
    fontSize: 24,
  );

  static TextStyle? get _subtitle1 => _poppinsTextTheme.subtitle1?.copyWith(
    fontSize: 16,
  );

  static TextStyle? get _button => _poppinsTextTheme.button?.copyWith(
    fontSize: 14,
    color: AppColor.buttonTextColor,
  );

  static TextStyle? get _bodyText2 => _poppinsTextTheme.bodyText2?.copyWith(
    fontSize: 14,
    wordSpacing: 0.25,
    letterSpacing: 0.25,
    height: 1.5,
  );

  static TextStyle? get _caption => _poppinsTextTheme.caption?.copyWith(
    fontSize: 14,
    wordSpacing: 0.25,
    letterSpacing: 0.25,
    height: 1.5,
  );

  static TextTheme darkTextTheme() => TextTheme(
    headline6: _headline6?.copyWith(color: AppColor.darkPrimaryTextColor),
    headline5: _headline5?.copyWith(color: AppColor.darkPrimaryTextColor),
    subtitle1: _subtitle1?.copyWith(color: AppColor.darkPrimaryTextColor),
    bodyText2: _bodyText2?.copyWith(color: AppColor.darkPrimaryTextColor),
    button: _button,
    caption: _caption?.copyWith(color: AppColor.darkPrimaryTextColor),
  );

  static TextTheme lightTextTheme() => TextTheme(
    headline6: _headline6?.copyWith(color: AppColor.lightPrimaryTextColor),
    headline5: _headline5?.copyWith(color: AppColor.lightPrimaryTextColor),
    subtitle1: _subtitle1?.copyWith(color: AppColor.lightPrimaryTextColor),
    bodyText2: _bodyText2?.copyWith(color: AppColor.lightPrimaryTextColor),
    button: _button,
    caption: _caption?.copyWith(color: AppColor.lightPrimaryTextColor),
  );
}

extension ThemeTextExtension on TextTheme {
  TextStyle? get darkHintStyle =>
      bodyText2?.copyWith(color: AppColor.darkSecondaryTextColor);
  TextStyle? get lightHintStyle =>
      subtitle2?.copyWith(color: AppColor.lightSecondaryTextColor);
  TextStyle? get tabSelectedTextStyle => caption?.copyWith(fontSize: 12);
  TextStyle? get tabUnSelectedTextStyle => caption?.copyWith(fontSize: 10);

  TextStyle? get cardTextStyle => caption?.copyWith(
    fontSize: 10,
    fontWeight: FontWeight.w700,
    color: Colors.black,
  );
  TextStyle? get tagTextStyle => caption?.copyWith(
    fontSize: 10,
  );
  TextStyle? get ratingTextStyle => caption?.copyWith(
    fontSize: 10,
  );
}

enum Themes {
  dark,
  light
}

 

custom-appbar

import 'package:aone/core/app_strings.dart';
import 'package:aone/presentation/journey/screens/search.dart';
import 'package:flutter/material.dart';

class CustomAppBar extends StatelessWidget{
  String type;
  CustomAppBar(this.type);
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () =>showSearch(
        context: context, delegate: ApSearchDelegate(type),
      ),
      child: AppBar(
        title: TextField(
          enabled: false,
          decoration: InputDecoration(hintText: Strings.search_books),textAlign: TextAlign.center,),
        actions:[  Icon(Icons.search),
        ],
        backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
      ),
    );
  }

}

 

 

Step 5: book,category and filer_model, these are the model classes used in application. We will create these classes under data/entities folder

 

book.dart

class Book{
  late String id;
  late String title;
  late String author;
  late String img;
  late int is_paid;
  late int price;
  late String thumb_nail;
  late String details;
  late String source;
  late String download_path;
  late int category_id;
  late String catebory_name;
  Book(this.id,this.title,this.author,this.img,this.is_paid,this.price,this.thumb_nail,this.details,this.source,this.download_path,this.category_id,this.catebory_name);

  factory Book.fromJSON(Mapjson)
  {
    return Book(
      json['id'],
      json['title'],
      json['author'],
        json.containsKey("img")?json['img']:"",
        json.containsKey("is_paid")?(int.parse(json['is_paid'])):0,
        json.containsKey("price")?(int.parse(json['price'] )):0,
      json['thumb_nail'],
        json.containsKey("details")?json['details']:"",
        json.containsKey("source")?json['source']:"",
        json.containsKey("download_path")?json['download_path']:"",
    int.parse(json['category_id'] ),
        json.containsKey("catebory_name")?json['catebory_name']:""
    );
  }
}

class BookListResult{
  List booklist;
  BookListResult(this.booklist);
  factory BookListResult.fromJSON(Map json){

    var list=List.empty(growable: true);
    if(json['booklist']!=null)
      {
        json["booklist"].forEach((value) {
          list.add(Book.fromJSON(value));
        });
      }

    return BookListResult(list);
  }

}

 

category.dart

class Category{
  Category(this.id,this.name,this.selected);
  String id;
  String name;
  bool selected=false;

  factory Category.fromJSON(Mapjson)
  {
    return Category(json['id'],json['name'],false);
  }
}

class CategoryList{
  List catlist;
  CategoryList(this.catlist);


  factory CategoryList.fromJSON(Mapjson)
  {
    var datalist=List.empty(growable: true);
    json['categorylist'].forEach((v){
      datalist.add(Category.fromJSON(v));
    });

    return CategoryList(datalist);
  }
}

 

filter.dart

class BookF{
  String filter_id;
  String filter_title;
  bool isSelected;
  BookF(this.filter_id,this.filter_title,this.isSelected);

}

 

Step 6:

We are done with Network and Model classes let's come to presentation layer. This present layer contains blocs and journeys classes.

Let's create bloc classes. Every bloc class contains two classes one is for bloc and other is for state. In this application we have below bloc classes book,category and connectivity blocs, these classes contains state classes respectively

book cubit

import 'package:aone/core/apis/client_request.dart';
import 'package:aone/core/apis/constants.dart';
import 'package:aone/core/apis/fake_data.dart';
import 'package:aone/data/entities/book.dart';
import 'package:aone/data/entities/category.dart';
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
import 'dart:convert';

part 'book_state.dart';

class BookCubit extends Cubit {
  ClientRequest request;
  BookCubit(this.request) : super(BookInitial());
int page=0;
  Future<void>getBookList(String id, int start) async
    {
      if(state is BookLoading) return;
      final current_state=state;


      var oldBooks=[];
      if(current_state is BookLoaded)
        {
          oldBooks=current_state.booklist;
        }
      
      emit(BookLoading(oldBooks,isFirst: (page==1)));
      Maphm=Map();
      hm['id']=id;
      hm['start']=page*6;
      final responseString= await request.get(ApiConstants.book_list, "", hm, false);
      page++;
      print(responseString);
      var newLIst=BookListResult.fromJSON(json.decode(responseString)).booklist;
      var oldList=(state as BookLoading).oldlist;
      oldList.addAll(newLIst);
     emit( BookLoaded(oldList)) ;

    }

  Future<void>getBookListf(String id) async
  {
    Maphm=Map();
    hm['id']=id;
    final responseString= await request.get(ApiConstants.book_list, "", hm, false);
    print(responseString);
    emit( BookLoaded(BookListResult.fromJSON(json.decode(responseString)).booklist)) ;

  }

  Future<void>getBookDetail(String id) async
  {
    Maphm=Map();
    hm['id']=id;
    final responseString= await request.get(ApiConstants.book_details, "", hm, false);
    print(responseString);
    emit( BookLoaded(BookListResult.fromJSON(json.decode(responseString)).booklist)) ;

  }
  Future<void>searchBook(String search,var filter_ids,var isFirstPage) async
  {

    if(state is BookLoading) return;
    final current_state=state;


    var oldBooks=[];
    if(current_state is BookLoaded)
    {
      if(isFirstPage)
        current_state.booklist.clear();
      oldBooks=current_state.booklist;
    }
    if(isFirstPage)
      page=0;
    emit(BookLoading(oldBooks,isFirst: isFirstPage));
    Maphm=Map();
    hm['search']=search;
    if(filter_ids!=null)
      hm['filter_ids']=filter_ids;
    hm['start']=page*6;
    final responseString= await request.get(ApiConstants.book_search, "", hm, false);
    page++;
    print(responseString);
    var newLIst=BookListResult.fromJSON(json.decode(responseString)).booklist;
    var oldList=(state as BookLoading).oldlist;
    oldList.addAll(newLIst);
    emit( BookLoaded(oldList)) ;


    print("search on search $search");

   /* final responseString= await request.get(ApiConstants.book_search, "", hm, false);
    print(responseString);
    emit( BookLoaded(BookListResult.fromJSON(json.decode(responseString)).booklist)) ;*/

  }


}

 

book_state

part of 'book_cubit.dart';

@immutable
abstract class BookState {
  const BookState();
}

class BookInitial extends BookState {}
class BookLoaded extends BookState {
   final Listbooklist;
   const BookLoaded(this.booklist);
}

class BookLoading extends BookState {
  final Listoldlist;
  final bool isFirst;
  const BookLoading(this.oldlist,{this.isFirst=false});
}

 

category_cubit

import 'dart:convert';

import 'package:aone/core/apis/client_request.dart';
import 'package:aone/core/apis/constants.dart';
import 'package:aone/data/entities/category.dart';
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';

part 'category_state.dart';

class CategoryCubit extends Cubit {


  ClientRequest request;
  CategoryCubit(this.request) : super(CategoryInitial());
  Future<void>getCategoryList() async
  {
    final responseString= await request.get(ApiConstants.book_category, "", null, false);
    print(responseString);
    emit( CategoryLoaded(CategoryList.fromJSON(json.decode(responseString)).catlist)) ;

  }
}

 

category_state

part of 'category_cubit.dart';

@immutable
abstract class CategoryState {
  const CategoryState();
}

class CategoryInitial extends CategoryState {}
class CategoryLoaded extends CategoryState {
  final Listcatlist;
  const CategoryLoaded(this.catlist);
}

 

Connectivity_cubit

import 'package:bloc/bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';

part 'connectivity_state.dart';

class ConnectivityCubit extends Cubit {
  Connectivity _connectivity;
  ConnectivityCubit(this._connectivity) : super(ConnectivityInitial());

  Future<void>getConnectivityStatus() async
  {
    late ConnectivityResult result;
    try {
      result = await _connectivity.checkConnectivity();
    } on PlatformException catch (e) {
      print(e.toString());
      return;
    }
    emit( ConnectivityChanged(result)) ;

  }
}

 

Connectivity_state

part of 'connectivity_cubit.dart';

@immutable
abstract class ConnectivityState {}

class ConnectivityInitial extends ConnectivityState {}

class ConnectivityChanged extends ConnectivityState{
  ConnectivityResult result;
  ConnectivityChanged(this.result);
}

 

Step 7: Let's create journey classes

Journeys contains two folder

Widgets: book_widget,book_widget_v,header_text,loading

Screens :book_details,book_list,error_page,filer_books,homepage,network_error,search screens

book_details.dart

import 'package:aone/core/apis/client_request.dart';
import 'package:aone/data/entities/book.dart';
import 'package:aone/presentation/blocs/book_cubit.dart';
import 'package:aone/presentation/journey/widgets/header_text.dart';
import 'package:aone/presentation/journey/widgets/loading.dart';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:url_launcher/url_launcher.dart';
class BookDetails extends StatelessWidget{
  BookCubit _bookCubit=BookCubit(ClientRequest(Dio()));
  Book book;
  BookDetails(this.book);
  @override
  Widget build(BuildContext context) {
    Size size=MediaQuery.of(context).size;
    return Scaffold(
      appBar: AppBar(title: Text("Book Details"),),
      body: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Stack(
              alignment: Alignment.topCenter,
              children: [
                Container(
                  width: double.infinity,
                  height: 250,
                  decoration: BoxDecoration(
                    gradient:  RadialGradient(
                        colors: [Colors.white,Theme.of(context).primaryColorLight/* const Color(0xFF02BB9F)*/]
                    )/*LinearGradient(
                        colors: [Colors.lightGreen,Colors.lightGreenAccent, Colors.black87,Colors.black54])*/
                    /*image: DecorationImage(
                    fit: BoxFit.fill,
                    image: AssetImage("assets/images/aone.JPG"),
                  )*/,
                  borderRadius: BorderRadiusDirectional.only(bottomStart: Radius.circular(10),bottomEnd: Radius.circular(10))),
                child: Padding(padding: EdgeInsets.symmetric(horizontal: 24),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    SizedBox(height: 12,),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Expanded(child: Text(book.title,style: Theme.of(context).textTheme.headline5,)),
                        Image.network(book.img, height: 150,),


                      ],

                    ),
                    SizedBox(height: 10,),
                    Expanded(child: Text(book.author)),
                    Expanded(child: Text((book.is_paid==1)?"${book.price}":"Free")),
                  ],
                ),),
                ),

                Positioned(
                    bottom: 10,
                    right: 10,
                    child: FloatingActionButton(
                      elevation: 20,
                      backgroundColor: Theme.of(context).scaffoldBackgroundColor,
                      onPressed: (){
                        _launchInWebViewWithJavaScript((book.is_paid==1)?book.source:book.download_path);
                      },child: Text((book.is_paid==1)?"Buy ":"Read"),))
              ],
            ),
        BlocProvider.value(value: _bookCubit..getBookDetail(book.id), child: BlocBuilder(builder: (_,state){
                    if(state is BookInitial)
                    {
                       return Loading();
                    }else if(state is BookLoaded)
                    {
                      print("state.booklist.length ${state.booklist.length}");
                          if(state.booklist.length>0)
                          {
                            return  Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Card(
                                  color: Theme.of(context).cardColor,
                                  child: Padding(
                                    padding: const EdgeInsets.all(8.0),
                                    child: Html(

                                        shrinkWrap: true,
                                        data: state.booklist[0].details,
                                        onLinkTap: (url, ctx, map, el) {

                                          map.keys.forEach((element) {
                                            print("OnLink Tap element $element");
                                          });
                                        },
                                        style: {

                                        }),
                                  )),
                            );
                          }
                    }
                    return SizedBox.shrink();
        })),

          ],
        ),
      ),
    );
  }
  Future<void> _launchInWebViewWithJavaScript(String url) async {
    if (await canLaunch(url)) {
      await launch(
        url,
        forceSafariVC: true,
        forceWebView: true,
        enableJavaScript: true,
      );
    } else {
      throw 'Could not launch $url';
    }
  }
}

 

book_list.dart

import 'dart:async';

import 'package:aone/core/apis/client_request.dart';
import 'package:aone/core/custom_appbar.dart';
import 'package:aone/presentation/blocs/book_cubit.dart';
import 'package:aone/presentation/journey/widgets/book_widget.dart';
import 'package:aone/presentation/journey/widgets/book_widget_v.dart';
import 'package:aone/presentation/journey/widgets/loading.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

import 'package:flutter_bloc/flutter_bloc.dart';
class BookList extends StatelessWidget{
  ScrollController _controller=ScrollController();
  GlobalKey_globalKey=GlobalKey();
  String type;
  int start=0;
  bool isEnd=false;
  BookList(this.type);
  var booklist=[];
  BookCubit _bookCubit=BookCubit(ClientRequest(Dio()));

  handleController(context)
  {

    _controller.addListener(() {
      if(_controller.position.atEdge)
      {
        if(_controller.position.pixels!=0)
        {
          print("Page at End");if(!isEnd)
          _bookCubit.getBookList(type,start);
        }
      }
    });


  }
  @override
  Widget build(BuildContext context) {
    handleController(context);
   return Scaffold(
     key: _globalKey,
       appBar: AppBar(title: Text("ItBooks"),),
       body: Padding(
         padding: const EdgeInsets.all(8.0),
         child: BlocProvider.value(value: _bookCubit..getBookList(type,start),
             child: BlocBuilder(builder: (_,state){
               print(state);
               var isLoading=false;
               if(state is BookLoading&& state.isFirst)
               {
                 return Loading();
               }

               if(state is BookLoading)
                 {
                   isLoading=true;
                   booklist=state.oldlist;
                 }else if(state is BookLoaded)
                   {
                     booklist=state.booklist;
                   }
               if(booklist.length>0&&(booklist.length % 6)!=0)
                 {
                   isEnd=true;
                 }


                 return ListView.builder(
                   controller: _controller,
                   shrinkWrap: true,
                   scrollDirection: Axis.vertical,
                     itemCount: (booklist.length>0)?booklist.length+((isLoading)?1:0):0,
                   itemBuilder: (_,index){
                     if(index<=booklist.length) return Container(
                     width: MediaQuery.of(context).size.width,
                      child: BookWidgetV(  140,booklist[index])
                   ); else {
                     Timer(Duration(milliseconds: 30),(){
                       _controller.jumpTo(_controller.position.maxScrollExtent);
                     });
                       return Loading();
                     }
                 });

               return SizedBox.shrink();
             }
             )

         ),
       )
   );
  }

}

 

error_page.dart

import 'package:flutter/material.dart';

class ErrorPage extends StatelessWidget{
  String message;
  ErrorPage({required this.message});
  @override
  Widget build(BuildContext context) {

    return Scaffold(body: Center(child: Text(message),),);
  }

}

 

filter_dart

import 'dart:convert';

import 'package:aone/data/entities/filter_model.dart';

import 'package:aone/presentation/journey/widgets/header_text.dart';
import 'package:flutter/material.dart';

class FilterBook extends StatefulWidget{
  @override
  _FilterBookState createState() => _FilterBookState();
}

class _FilterBookState extends State {
  Listselected=List.empty(growable: true);
  bool isPaid=false;
  bool isFree=false;
  bool isLatest=false;
  bool isOld=false;
  bool isFilter=false;

  List filter_three = [
    BookF( "1","IT Books", false),
    BookF( "2","Horror", false),
    BookF( "3","Sports", false),
    BookF( "12","Horror", false),
    BookF( "13","Academic", false),
  ];

  @override
  Widget build(BuildContext context) {

    return Scaffold(

      backgroundColor: Colors.white,
      appBar: AppBar(
        leading: MaterialButton(
        onPressed: (){
          Navigator.pop(context,"");
        },child: Icon(Icons.arrow_back_ios,color:Colors.white)),
        backgroundColor: Colors.purple,
        actions: [
          (isFilter||selected.length>0)?MaterialButton(onPressed: (){
         setState(() {
           filter_three.forEach((element) {
             element.isSelected=false;
           });
           selected.clear();
           isFilter=false;
            isPaid=false;
            isFree=false;
            isLatest=false;
            isOld=false;
         });
        },child: Icon(Icons.clear,color:Colors.white),):SizedBox.shrink(),
        (isFilter||selected.length>0)?MaterialButton(onPressed: (){
          Mapfilters=Map();
          filters['isPaid']=(isPaid)?1:0;
          filters['isFree']=(isFree)?1:0;
          filters['Latest']=(isLatest)?1:0 ;
          filters['Old']=(isOld)?1:0 ;
          filters['cat']=(selected);

          Navigator.pop(context, jsonEncode(filters));


        },child: Text("Apply",style: TextStyle(color:Colors.white),)):SizedBox.shrink()
      ],),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Card(
          child
              : Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [

                MediumText("Sort By",Colors.red),
                SizedBox(height: 10,),

            Row(children: [
              Checkbox(
                  value: isPaid, onChanged: (value){
                    setState(() {
                      isPaid=value!;
                      isFilter=true;
                    });

              }), MediumText("Paid",Colors.red),

            ]),Row(children: [
                  Checkbox(
                      value: isFree, onChanged: (value){

                    setState(() {
                      isFree=value!;
                      isFilter=true;
                    });
                  }), MediumText("Free",Colors.red),

                ]),
                SizedBox(height: 20,),
                Divider(height: 2,color: Colors.grey,),

                MediumText("Sort By",Colors.deepPurple),
                SizedBox(height: 10,),
                Row(children: [
                  Checkbox(
                      value: isLatest, onChanged: (value){
                    setState(() {
                      isLatest=value!;
                    });

                  }), MediumText("Latest",Colors.deepPurple),

                ]),Row(children: [
                  Checkbox(
                      value: isOld, onChanged: (value){
                    setState(() {
                      isOld=value!;
                    });

                  }), MediumText("Old",Colors.deepPurple),

                ]),

                SizedBox(height: 20,),
                Divider(height: 2,color: Colors.grey,),
                MediumText("Filter By",Colors.blue),
                SizedBox(height: 10,),

                Wrap(
                  spacing: 8,
                  direction: Axis.horizontal,
                  children: techChips(filter_three,Colors.blue),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  List techChips (List _chipsList,color) {
    List chips = [];
    for (int i=0; i< _chipsList.length; i++) {
      Widget item = Padding(
        padding: const EdgeInsets.only(left:10, right: 5),
        child: FilterChip(
          selectedColor: color,
          label: Text(_chipsList[i].filter_title),
          labelStyle: TextStyle(color: Colors.white),
          backgroundColor: color,
          selected: _chipsList[i].isSelected,
          checkmarkColor: Colors.white,
          onSelected: (bool value)
          {

            if(value)
              {
                selected.add(_chipsList[i].filter_id);
              }else
                {
                  selected.remove(_chipsList[i].filter_id);
                }
            setState(() {
              _chipsList[i].isSelected = value;
            });


          },
        ),
      );
      chips.add(item);
    }
    return chips;
  }
}

 

homepage.dart

import 'dart:async';
import 'dart:convert';

import 'package:aone/core/apis/client_request.dart';
import 'package:aone/core/app_route.dart';
import 'package:aone/core/app_strings.dart';
import 'package:aone/core/custom_appbar.dart';
import 'package:aone/data/entities/category.dart';
import 'package:aone/presentation/blocs/book_cubit.dart';
import 'package:aone/presentation/blocs/category_cubit.dart';
import 'package:aone/presentation/blocs/connectivity_cubit.dart';
import 'package:aone/presentation/journey/screens/error_page.dart';
import 'package:aone/presentation/journey/screens/widgets/it_books.dart';
import 'package:aone/presentation/journey/widgets/loading.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'network_error.dart';

class HomePage extends StatelessWidget{
  CategoryCubit _catCubit=CategoryCubit(ClientRequest(Dio()));
  ConnectivityResult _connectionStatus = ConnectivityResult.none;
  final Connectivity _connectivity = Connectivity();
  ConnectivityCubit _connectivityCubit=ConnectivityCubit(Connectivity());
  late StreamSubscription _connectivitySubscription;

 /* Future initConnectivity() async {
    late ConnectivityResult result;
    try {
      result = await _connectivity.checkConnectivity();
    } on PlatformException catch (e) {
      print(e.toString());
      return;
    }

    return _updateConnectionStatus(result);
  }*/
  Future<void> _updateConnectionStatus(ConnectivityResult result) async {
    _connectivityCubit.emit(ConnectivityChanged(result));


  }
  @override
  Widget build(BuildContext context) {
   // initConnectivity();
    _connectivitySubscription =
        _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(actions: [
          MaterialButton(onPressed: ()async {
            var result= await Navigator.pushNamed(context,  AppRoutes.filter,);
            print(result);
           /* List _chipsList =result as List;
            print("String to Json: ${jsonEncode(_chipsList)}");
            _chipsList.forEach((element) {
              print(element);
            });*/
          },child: Icon(Icons.filter_tilt_shift_sharp),)
        ],),
        body: MultiBlocProvider(
        providers: [
        BlocProvider.value(value: _catCubit..getCategoryList(),
        ),
      BlocProvider.value(value: _connectivityCubit..getConnectivityStatus(),)

    ],  child:BlocBuilder(builder: (_,state) {

      if(state is ConnectivityChanged)
        {
          print(" state.result ${state.result}");
          if(state.result==ConnectivityResult.none)
            {
             // return NetworkError();
            }
        }
          return BlocBuilder(builder: (_,state){
            return SingleChildScrollView(
              child: Column(

                children: [

                  Container(
                    height: 150,
                    decoration:BoxDecoration(
                      image: DecorationImage(
                        fit: BoxFit.fill,
                        image: AssetImage("assets/images/aone.JPG"),
                      ),
                    ),
                  ),
                  Container(child: CustomAppBar(""),
                    decoration: BoxDecoration(border: Border(bottom: BorderSide(width: 1))),),
                  (state is BookInitial)?Loading():(state is CategoryLoaded)?Column(children: loadList(state),):SizedBox.shrink(),

                ],
              ),
            );
          },);
        })



        )

      ),
    );
  }
   List loadList(state)
  {

   var list=List.empty(growable: true);
    state.catlist.forEach((element) { list.add(ItBookBox(element));});
    return list;
  }

}

 

network_error.dart

import 'package:aone/presentation/journey/widgets/header_text.dart';
import 'package:flutter/material.dart';

class NetworkError extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
            image: DecorationImage(
              fit: BoxFit.fill,
              image: AssetImage("assets/images/aone.JPG"),
            ),

        ),
      child: Center(
      child: Card(
        elevation: 40,
        shadowColor: Colors.green,
        margin: EdgeInsets.symmetric(horizontal: 20),
        child: Container(
          height: 250,
          decoration: BoxDecoration(
          gradient:  RadialGradient(
          colors: [Colors.white,Colors.red/* const Color(0xFF02BB9F)*/]
    ),
    ),
          child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
          _getCloseButton(context),
          Padding(
            padding: EdgeInsets.fromLTRB(
                20,10, 20, 0),
            child: Column(
              children: [
                Icon(Icons.warning_amber_sharp,size: 64,color: Colors.red,),
                SizedBox(
                  height: 15,
                ),
                Text(
                  "Network Error",style: TextStyle(fontSize: 28,color: Colors.deepPurple),

                ),
                SizedBox(
                  height:  10,
                ),
                MediumText(
                  "Please check your connectivity",
                  Colors.white
                ),
                SizedBox(
                  height:  20,
                ),
              ],
            ),
          )
          ],
    ),
        ),
      ),
      ),
    )
    );
  }
  _getCloseButton(context) {
    return Padding(
      padding: const EdgeInsets.fromLTRB(0, 10, 10, 0),
      child: GestureDetector(
        onTap: () {

        },
        child: Container(
          alignment: FractionalOffset.topRight,
          child: GestureDetector(child: Icon(Icons.clear,color: Colors.red,),

            onTap: (){

            },),
        ),
      ),
    );
  }
}

 

search.dart

import 'dart:async';

import 'package:aone/core/apis/client_request.dart';
import 'package:aone/core/app_route.dart';
import 'package:aone/core/app_strings.dart';
import 'package:aone/presentation/journey/widgets/book_widget_v.dart';
import 'package:aone/presentation/journey/widgets/loading.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

import 'package:aone/presentation/blocs/book_cubit.dart';
import 'package:aone/presentation/journey/widgets/book_widget.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ApSearchDelegate extends SearchDelegate{
  BookCubit _bookCubit=BookCubit(ClientRequest(Dio()));
  var result;
  String type;
  int start=0;
  bool isAddListner=false;
  bool isEnd=false;
  bool isFirst=true;
  var booklist=[];
  ScrollController _controller=ScrollController();
  ApSearchDelegate( this.type)
      : super(searchFieldLabel: Strings.enter_book_name);

  handleController()
  {

    _controller.addListener(() {
      if(_controller.position.atEdge)
      {
        if(_controller.position.pixels!=0)
        {
          print("Page at End");
          if(!isEnd)
            _bookCubit.searchBook(type,result,isFirst);
        }
      }
    });


  }
  @override
  ThemeData appBarTheme(BuildContext context) => Theme.of(context);

  @override
  List buildActions(BuildContext context) {
    return [
      if (query.isNotEmpty)
        IconButton(
          icon: Icon(
            Icons.clear,
            color: Theme.of(context).dividerColor,
          ),
          onPressed: () {
            isFirst=true;
            booklist.clear();
            query = '';
          }
        ),
      MaterialButton(onPressed: ()async {
         result= await Navigator.pushNamed(context,  AppRoutes.filter,);
         isFirst=true;
         isEnd=false;
         booklist.clear();
         _bookCubit.searchBook(type,result,isFirst);
        print(result);

      },child: Icon(Icons.filter_tilt_shift_sharp),)
    ];
  }

  @override
  Widget buildLeading(BuildContext context) {
    return GestureDetector(
      onTap: () => close(context, null),
      child: Icon(
        Icons.arrow_back_ios,
        color: Theme.of(context).dividerColor,
      ),
    );
  }

  @override
  Widget buildResults(BuildContext context) {
    FocusScope.of(context).unfocus();
    _bookCubit.searchBook(type,result,isFirst);
      return SizedBox.shrink();
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    start=0;
    isFirst=true;
    //FocusScope.of(context).unfocus();
    if(!isAddListner) {
      handleController();
      isAddListner=true;
    }
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: BlocProvider.value(value: _bookCubit..searchBook(query,result,isFirst),
          child: BlocBuilder(builder: (_,state){

            print(state);
            var isLoading=false;
            if(state is BookLoading&& state.isFirst)
            {
              return Loading();
            }

            if(state is BookLoading)
            {
              isLoading=true;
              booklist=state.oldlist;
            }else if(state is BookLoaded)
            {
              booklist=state.booklist;
            }
            if(booklist.length>0&&(booklist.length % 6)!=0)
            {
              isEnd=true;
            }

            isFirst=!(booklist.length>0);

            print(state);
            if(state is BookInitial)
            {
              return Loading();
            }else if(state is BookLoaded)
            {
              return ListView.builder(
                  controller: _controller,
                  shrinkWrap: true,
                  scrollDirection: Axis.vertical,
                  itemCount:(booklist.length>0)?booklist.length+((isLoading)?1:0):0,
                  itemBuilder: (_,index){
                    if(index<=booklist.length) return Container(
                        width: MediaQuery.of(context).size.width,
                        child: BookWidgetV(  140,state.booklist[index])
                    ); else {
                      Timer(Duration(milliseconds: 100),(){
                        //_controller.jumpTo(_controller.position.maxScrollExtent);
                      });
                      return Loading();
                    }


                  });;
            }
            return SizedBox.shrink();
          }
          )

      ),
    );
  }

}

 

it_books.dart

import 'package:aone/core/apis/client_request.dart';
import 'package:aone/core/app_route.dart';
import 'package:aone/core/app_strings.dart';
import 'package:aone/data/entities/category.dart';
import 'package:aone/presentation/blocs/book_cubit.dart';
import 'package:aone/presentation/journey/widgets/book_widget.dart';
import 'package:aone/presentation/journey/widgets/header_text.dart';
import 'package:aone/presentation/journey/widgets/loading.dart';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class ItBookBox extends StatelessWidget{
  Category category;
  BookCubit _bookCubit=BookCubit(ClientRequest(Dio()));
  ItBookBox(this.category);

  @override
  Widget build(BuildContext context) {
    return BlocProvider.value(value: _bookCubit..getBookListf(category.id),
    child: BlocBuilder(builder: (_,state){
      if(state is BookInitial)
        {
          return Loading();
        }else if(state is BookLoaded)
          {
            print("state.booklist.length ${state.booklist.length}");
            if(state.booklist.length>0)
              {
                return Container(
                  margin: EdgeInsets.symmetric(vertical: 8,horizontal: 12),
                  height: 250,
                  child: Column(
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          HeaderText(category.name),

                          TextButton(
                              onPressed:(){
                                print("On Presses");
                                Navigator.pushNamed(context,  AppRoutes.booklist,
                                  arguments: category.id,);
                                /*rootNavKey.currentState?.pushNamed(
                    AppRoutes.booklist,
                    arguments: 1,
                  );*/
                              },
                              child:Text( Strings.see_all,
                                style: Theme.of(context).textTheme.caption,)

                          )
                        ],
                      ),
                      Divider(height: 1,),
                      Expanded(child: ListView.builder(
                          scrollDirection: Axis.horizontal,
                          itemCount: state.booklist.length,
                          itemBuilder: (_,index){
                            return Container(
                                width: 140,

                                child: BookWidget(  140, 100,state.booklist[index])
                            );
                          }))
                    ],
                  ),
                );
              }

          }
      return SizedBox.shrink();
    },),) ;

  }

}

 

 

widget classes

book_widget.dart

import 'package:aone/core/app_route.dart';
import 'package:aone/data/entities/book.dart';
import 'package:aone/data/entities/category.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class BookWidget extends StatelessWidget{
  double height=100;
  double width=140;
  Book book;
  BookWidget(this.width,this.height, this. book);
  @override
  Widget build(BuildContext context) {
    return Card(
      color: Theme.of(context).cardColor,
      elevation: 5,
      child: Column(
        children: [
          (book.thumb_nail.endsWith("svg"))?SvgPicture.network(

            book.thumb_nail,
            width: width,
            height: height,
            placeholderBuilder: (BuildContext context) => Container(
                padding: const EdgeInsets.all(30.0),
                child: const CircularProgressIndicator()),
          ): Container(
            width: width,
            height: height,
            decoration: BoxDecoration(
              image: DecorationImage(
                fit: BoxFit.fill,
                image: NetworkImage(book.thumb_nail),
              ),
            ),
          ),
          // FittedBox(child: Image.asset("assets/images/aone.JPG",width: 140,height: 80,),fit: BoxFit.fill,),

          Expanded(child: Stack(children: [
            Padding(
              padding: const EdgeInsets.only(left:8.0),
              child: Text(book.title,maxLines: 2,),
            ),
            Align(alignment: Alignment.bottomCenter,
                child: MaterialButton(
                  height: 28,
                  shape: RoundedRectangleBorder(side: BorderSide(width: 1,color:Colors.black ),borderRadius:  BorderRadius.all(Radius.circular(8))),
                  onPressed: (){Navigator.pushNamed(context,  AppRoutes.bookdetails,
                  arguments: book,);},child: Text("View"),)/*Container(
                    margin: EdgeInsets.symmetric(vertical: 8),
                    decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor,
                        shape:BoxShape.rectangle,borderRadius: BorderRadius.all(Radius.circular(8)),border:Border(bottom: BorderSide(width: 1),top: BorderSide(width: 1),left: BorderSide(width: 1),right: BorderSide(width: 1))),
                    child:  Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 16,vertical: 1),
                      child: InkWell(child: Text("View"),onTap: (){
                        Navigator.pushNamed(context,  AppRoutes.bookdetails,
                          arguments: book,);
                      },),
                    ))*/)
          ],))
        ],
      ),
    );
  }

}

 

 

book_widget_v.dart

import 'package:aone/core/app_route.dart';
import 'package:aone/data/entities/book.dart';
import 'package:aone/data/entities/category.dart';
import 'package:aone/presentation/journey/widgets/header_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class BookWidgetV extends StatelessWidget{
  double height=100;

  Book book;
  BookWidgetV(this.height, this. book);
  @override
  Widget build(BuildContext context) {
    return Card(
      color: Theme.of(context).cardColor,
      elevation: 5,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          (book.thumb_nail.endsWith("svg"))?SvgPicture.network(

            book.thumb_nail,
            width: 120,
            height: height,
            placeholderBuilder: (BuildContext context) => Container(
                padding: const EdgeInsets.all(30.0),
                child: const CircularProgressIndicator()),
          ):  Container(
            width: 120,
            height: height,
            decoration: BoxDecoration(
              image: DecorationImage(
                fit: BoxFit.fill,
                image: NetworkImage(book.thumb_nail),
              ),
            ),
          ),
          // FittedBox(child: Image.asset("assets/images/aone.JPG",width: 140,height: 80,),fit: BoxFit.fill,),

          Expanded(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Padding(
                  padding: const EdgeInsets.only(left:8.0,right:8.0),
                  child: MediumText(book.title,Colors.black),
                ),
                SizedBox(height: 10,),
                Padding(
                  padding: const EdgeInsets.only(left:8.0,right:8.0),
                  child: Text(" ${book.author}",style: TextStyle(color: Colors.brown),),
                ),

                Padding(
                  padding: const EdgeInsets.only(left:12.0,right:8.0),
                  child: MaterialButton(

                    height: 28,
                    shape: RoundedRectangleBorder(side: BorderSide(width: 1,color:Colors.black ),borderRadius:  BorderRadius.all(Radius.circular(8))),
                    onPressed: (){Navigator.pushNamed(context,  AppRoutes.bookdetails,
                      arguments: book,);},child: Text("View"),),
                )
              ],
            ),
          ),

        ],
      ),
    );
  }

}

 

header_text.dart

import 'package:flutter/material.dart';

class HeaderText extends StatelessWidget{
String title;
  HeaderText(this.title);

  @override
  Widget build(BuildContext context) {

    return Text(title,style: TextStyle(fontSize: 20),);
  }}


class MediumText extends StatelessWidget{
  String title;
  Color color;
  MediumText(this.title, this.color);

  @override
  Widget build(BuildContext context) {

    return Text(title,style: TextStyle(fontSize: 17,color:this.color),);
  }}

 

loading.dart

import 'package:flutter/material.dart';

class Loading extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      child: Center(child: CircularProgressIndicator( color: Colors.lightGreenAccent,),),
    );
  }

}

 

Step 8:

Now finally add our main.dart

import 'dart:async';

import 'package:aone/core/app_themes.dart';
import 'package:aone/presentation/journey/screens/error_page.dart';
import 'package:aone/presentation/journey/screens/homepage.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'core/app_route.dart';
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {


  @override
  Widget build(BuildContext context) {
    return  MaterialApp(
      key: rootNavKey,
      title: 'Aone',
      theme:  AppTheme.init(context, Themes.light),
      initialRoute: AppRoutes.landing,
      onGenerateRoute: RouteGenerator.generateRoute,
    );
  }
}


 

Now let's run the application

Flutter Ebook - How to work with bloc cubit in flutter

 

Flutter Ebook Application

 

Flutter Clean Architecture

 

Flutter check network connectivity

 

Flutter Ebook details page with read and buy now option

 

Download Source code

 

 

 


Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

71 Views

Subscribe For Daily Updates

Flutter Questions
Android Questions