简体   繁体   中英

Flutter/Firestore - Implementing a "pagination" on a dynamic listview in a streambuilder

I have the logic figured and it works but I'm missing something because the only way this works is when I replace the array with the next "page" or documents but when I do a .addAll() to it, it gets messy. The same first documents get readded and a few new ones gets included as well but not all that was supposed to be included.

Code :

ScrollController _scrollController = ScrollController();
List<Message> _messages = [];
List<dynamic> _startAfter = [DateTime.now()];

...

@override
void initState() {
    super.initState();
    this._scrollController.addListener(() {
      if (this._scrollController.position.minScrollExtent + this._scrollController.position.pixels <= -15.0) {
        setState(() {
          this._startAfter = [this._messages.first.createdAt.toDate()];
        });
      }
    });
}

...

Column(
  children: <Widget>[
    Expanded(
      child: StreamBuilder<List<Message>>(
          stream: APIs().chats.messagesStream(chatID: widget.chat.chatID, orderBy: 'createdAt', descending: true, startAfter: this._startAfter, limit: 10),
          builder: (context, snapshot) {
            print(this._startAfter);
            switch (snapshot.connectionState) {
              case ConnectionState.waiting:
                {
                  return PAIndicator();
                }
              default:
                {
                  if (snapshot.hasData) {    
                    this._messages = snapshot.data; // Having the issue here.

                    // this._messages.addAll(snapshot.data); Causes problems when rebuilding

                    return MessagesList(
                      scrollController: this._scrollController,
                      messages: this._messages,
                      aUser: widget.aUser,
                    );
                  } else {
                    return ListView();
                  }
                }
            }
          }),
    ),
  // ...
  ]
)

I noticed the bug only happens when it's being rebuilt.

When the data is retrieved it replaces what's in the array, how can I just append the data instead of just replacing it or giving multiple same values of the same messages when the .addAll() is used without worry of the ui being rebuilt, like if the keyboard shows and closes?

Also, how can I make sure that if there are no more documents it doesn't get rebuilt or calls firebase? (Solved it, now just the main question above is left)

Figured out the solution for anyone who needs it. The only problem is that the items just get added to the list so it doesn't look pretty UI/UX wise. Feel free to add that solution if y'all have one. I tried AnimatedList but that didn't work because of the state issue, and I'm not aware of a workaround yet.

NOTE: FOR SOME REASON IT DOESN"T NOT LISTEN TO NEW MESSAGES FROM EITHER USER, I HAVE TO RE-ENTER THE CHAT TO SEE THE NEW MESSAGES, help with that pls.

GlobalKey<AnimatedListState> _listKey = GlobalKey();
ScrollController _scrollController = ScrollController();
List<Message> _messages = [];
List<dynamic> _startAfter = [DateTime.now()];
int _messagesLimit = 10;
bool _hasMoreMessages = false;

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

  if (Platform.isIOS) {
    this._scrollController.addListener(() {
      if (this._scrollController.position.pixels >= this._scrollController.position.maxScrollExtent + 150.0) {
        this._checkForOldMessages();
      }
    });
  }
}

@override
Widget build(BuildContext context) {
  Widget w = WillPopScope(
      child: Stack(
        children: <Widget>[
          Column(
            children: <Widget>[
              Expanded(child: this._streamBuilderWidget()),
              // …
            ],
          ),
        ],
      ),
      onWillPop: () {});

  …
}

Widget _streamBuilderWidget() {
    return StreamBuilder<List<Message>>(
        initialData: this._messages,
        stream: APIs().chats.messagesStream(chatID: widget.chat.chatID, orderBy: 'createdAt', descending: true, startAfter: this._startAfter, limit: this._messagesLimit),
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              {
                return PAIndicator();
              }
            default:
              {
                if (snapshot.data.length < this._messagesLimit) {
                  this._hasMoreMessages = false;
                } else {
                  this._hasMoreMessages = true;
                }

                snapshot.data.forEach((m) {
                  print(m.message);
                });

                if (!ListEquality().equals(this._messages, snapshot.data)) {
                  snapshot.data.forEach((m) {
                    this._messages.add(m);
                  });
                } else {
                  print('nonononono');
                }

                // Doesn't Work...
                // if (mounted) this._listKey.currentState.insertItem(this._messages.length - 1, duration: Duration(milliseconds: 500)); 

                return Platform.isIOS
                    ? MessagesList(mKey: this._listKey, scrollController: this._scrollController, messages: this._messages, aUser: widget.aUser)
                    : RefreshIndicator(
                    child: MessagesList(mKey: this._listKey, scrollController: this._scrollController, messages: this._messages, aUser: widget.aUser),
                    onRefresh: () async {
                      await Future.delayed(Duration(seconds: 1));

                      this._checkForOldMessages();

                      return null;
                    });
              }
          }
        });
  }

_checkForOldMessages() {
  if (this._hasMoreMessages) {
    print('Adding More...');
    setState(() {
      this._startAfter = [this._messages.last.createdAt.toDate()];
    });
    this._streamBuilderWidget();
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM