draw-dev / DRAW

DRAW: The Dart Reddit API Wrapper
BSD 3-Clause "New" or "Revised" License
87 stars 24 forks source link

replaceMore() assertion error suggests _insertComment operating on an existing comment #180

Open inhumantsar opened 4 years ago

inhumantsar commented 4 years ago

so i've got a stateless ListView based widget filled by a viewmodel and a singleton service. when i scroll to the end of the ListView, the widget successfully relays a call to replaceMore() and those new comments pop in to the ListView.

When I scroll to the new bottom and encounter the second MoreComments object, I get an exception. The assertion it fails on suggests to that the insert is being called on a Comment which already exists in the Submission's comment list.

Not sure if this is a bug or pebkac. I don't see how replaceMore could run into a comment that already exists if i'm awaiting it between calls.

[RedditService] loading discussion thread...
[RedditService] found dt: https://redd.itgt9vt5
[RedditService] dt populated: Discussion Thread (75 comments)
... scroll to bottom ...
[DtViewModel] found morecomments: fsab9qd
[RedditService] asked to replace MoreComments objs.  status: false currentDt.comments.length=75
[RedditService] replacement complete. status: false currentDt.comments.length=84
... scroll to new bottom ...
[DtViewModel] found morecomments: fsabd63
[RedditService] asked to replace MoreComments objs.  status: false currentDt.comments.length=84
[RedditService] 'package:draw/src/models/comment_forest.dart': Failed assertion: line 41 pos 12: '(comment is MoreComments) ||
                        ((comment…
// widget
...
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('DT'),
        backgroundColor: Colors.amber,
      ),
      body: ListView.builder(
        itemCount: this.vm.dt?.comments?.length ?? 0,
        shrinkWrap: true,
        itemBuilder: (context, index){
          if (this.vm.dt?.comments == null) return const SizedBox.shrink();
          if (this.vm.dt.comments.length <= index) return const SizedBox.shrink();
          var rawcomm = this.vm.dt.comments[index];
          if (rawcomm == null) return SizedBox.shrink();
          if (rawcomm is MoreComments) {
            this.vm.log.v('found morecomments: ${rawcomm.id}');
            this.vm.replaceMoreComments();
            return const SizedBox.shrink();
          }
          return CommentCardWidget(TacoComment.fromComment(rawcomm));
        },
      )
  }
}
// viewmodel extends ChangeNotifier
...
  Submission get dt => this.service.currentDt;
...
  void replaceMoreComments() => this.service.replaceMoreComments().whenComplete(() => this.notifyListeners());
...
// service singleton
  ...
  Future<void> replaceMoreComments() async {
    if (this.replacingMoreComments == false) {
      this.log.v('asked to replace MoreComments objs.  status: ${this.replacingMoreComments} currentDt.comments.length=${this.currentDt.comments.length}');
      this.replacingMoreComments = true;
      try {
        await this.currentDt.comments.replaceMore();
      } catch(e) {
        this.log.e(e.toString());
      }
      this.replacingMoreComments = false;
      this.log.v('replacement complete. status: ${this.replacingMoreComments} currentDt.comments.length=${this.currentDt.comments.length}');
    } else this.log.v('skipping replace, status: ${this.replacingMoreComments}');
  }