unice
unice

Reputation: 2842

how to use infinite_scroll_pagination for bloc pattern

I'm currently learning and converting my code to BLoc pattern. Before I'm using flutter_pagewise ^1.2.3 for my infinite scroll using Future<> but I don't know how to use it using bloc or is it compatible with it.

So now I'm trying infinite_scroll_pagination: ^2.3.0 since it says in its docs that it supports Bloc. But I don't understand the example code in the docs for bloc. Can you give me a simple example of how to use it with bloc? I'm currently using flutter_bloc: ^6.1.3.

Here are my bloc script:

class TimeslotViewBloc extends Bloc<TimeslotViewEvent, TimeslotViewState> {
  final GetTimeslotView gettimeslotView;

  TimeslotViewBloc({this.gettimeslotView}) : super(TimeslotViewInitialState());

  @override
  Stream<TimeslotViewState> mapEventToState(
    TimeslotViewEvent event,
  ) async* {
    if (event is GetTimeslotViewEvent) {
      yield TimeslotViewLoadingState();
      final failureOrSuccess = await gettimeslotView(Params(
        id: event.id,
        date: event.date,
      ));
      yield* _eitherLoadedOrErrorState(failureOrSuccess);
    }
  }

  Stream<TimeslotViewState> _eitherLoadedOrErrorState(
    Either<Failure, List<TimeslotViewEntity>> failureOrTrivia,
  ) async* {
    yield failureOrTrivia.fold(
      (failure) => TimeslotViewErrorState(
          message: _mapFailureToMessage(failure), failure: failure),
      (result) => TimeslotViewLoadedState(result),
    );
  }


//Bloc Events----------------------------------------
abstract class TimeslotViewEvent extends Equatable {
  const TimeslotViewEvent();
  @override
  List<Object> get props => [];
}

class GetTimeslotViewEvent extends TimeslotViewEvent {
  final String id;
  final String date;
  final int offset;
  final int limit;

  GetTimeslotViewEvent(
      {this.id,
      this.date,
      this.offset,
      this.limit});
}

//Bloc States----------------------------------------
abstract class TimeslotViewState extends Equatable {
  const TimeslotViewState();
  @override
  List<Object> get props => [];
}

class TimeslotViewLoadingState extends TimeslotViewState {}

class TimeslotViewLoadedState extends TimeslotViewState {
  final List<TimeslotViewEntity> records;

  TimeslotViewLoadedState(this.records);
  @override
  List<Object> get props => [records];
}

UPDATE: Here is the revised code from Davii that works for me

@override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => _timeLotBloc,
      child: BlocListener<TimeslotViewBloc, TimeslotViewState>(
        listener: (context, state) {
          if (state is TimeslotViewLoadedState) {

            //Save record count instead of records list
            totalRecordCount += state.records.length; 
            final _next = 1 + totalRecordCount;

            final isLastPage = state.records.length < PAGE_SIZE;
            if (isLastPage) {
              _pagingController.appendLastPage(state.records);
            } else {
              _pagingController.appendPage(state.records, _next);
            }
          }
          if (state is TimeslotViewErrorState) {
            _pagingController.error = state.error;
          }
          
        },
        //Removed pagedListview from bloc builder
        child: PagedListView<int, TimeslotViewEntity>(
            pagingController: _pagingController,
            builderDelegate: PagedChildBuilderDelegate<TimeslotViewEntity>(
            itemBuilder: (context, time, index) => TimeslotViewEntityListItem(
            character: time,
          ),
        ),
      ),),
      );
  }

Upvotes: 4

Views: 9926

Answers (1)

Davii The King
Davii The King

Reputation: 509

class PaginatedList extends StatefulWidget {
  const PaginatedList({Key? key}) : super(key: key);

  @override
  _PaginatedListState createState() => _PaginatedListState();
}

class _PaginatedListState extends State<PaginatedList> {
  //*bloc assuming you use getIt and injectable
  late final _timeLotBloc = getIt<TimeslotViewBloc>();

  List<TimeslotViewEntity> records = [];

  //*initialize page controller
  final PagingController<int, TimeslotViewEntity> _pagingController =
      PagingController(firstPageKey: 0);

  @override
  void initState() {
    super.initState();

    //*so at event add list of records
    _pagingController.addPageRequestListener(
      (pageKey) => _timeLotBloc
          .add(GetTimeslotViewEvent(records: records, offset: pageKey,limit: 10)),
    );
  }

  @override
  void dispose() {
    super.dispose();
    _timeLotBloc.close();
    _pagingController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => _timeLotBloc,
      child: BlocListener<TimeslotViewBloc, TimeslotViewState>(
        listener: (context, state) {
          if (state is TimeslotViewLoadedState) {

            records =state.records;
          
            //forget about existing record
            //about the last page, fetch last page number from 
            //backend

            int lastPage = state.lastPage
            final _next = 1 + records.length;

            if(_next>lastPage){
              _pagingController.appendLastPage(records);
              }
            else{
               _pagingController.appendPage(records, _next);
            }
            
            
          }
          if (state is TimeslotViewErrorState) {
            _pagingController.error = state.error;
          }
          
        },child: BlocBuilder<TimeslotViewBloc,TimeslotViewState>(
          builder: (context,state)=> PagedListView<int, TimeslotViewEntity>(
            pagingController: _pagingController,
            builderDelegate: PagedChildBuilderDelegate<TimeslotViewEntity>(
            itemBuilder: (context, time, index) => TimeslotViewEntityListItem(
            character: time,
          ),
        ),
      ),),
      ),
    );
  }
}

now on the bloc event class

class GetTimeslotViewEvent extends TimeslotViewEvent {
  final String id;
  final String date;
  final int offset;
  final int limit;
  //add this on event
  final List<TimeslotViewEntity> records;

  GetTimeslotViewEvent({
    this.id,
    this.date,
    this.offset,
    this.limit,
    required this.records,
  });
}

on state class

class TimeslotViewLoadedState extends TimeslotViewState {
  final List<TimeslotViewEntity> records;
  final List<TimeslotViewEntity> existingRecords;
  TimeslotViewLoadedState(this.records, this.existingRecords);
  @override
  List<Object> get props => [records, existingRecords];
}

and on bloc now

 yield* _eitherLoadedOrErrorState(failureOrSuccess,event);
  Stream<TimeslotViewState> _eitherLoadedOrErrorState(
    Either<Failure, List<TimeslotViewEntity>> failureOrTrivia,
    GetTimeslotViewEvent event,
  ) async* {
    yield failureOrTrivia.fold(
      (failure) => TimeslotViewErrorState(
          message: _mapFailureToMessage(failure), failure: failure),
          //existing records from the event,
      (result) => TimeslotViewLoadedState(result,event.records),
    );
  }

yap this method worked on me

Upvotes: 7

Related Questions