Skip to content

Comment API

The Comment API offers a powerful and simple way to add comment feature to your app. It's versatile, perfect for things like blog comments, product reviews, or photo feedback.

It offers a complete set of UI/UX widgets and logics for managing comments including but not limited to CRUD, file uploading, likes, and much more.

Overview

  • It is best to use the SliverListView as it can get the comments little by little as user scrolls the screen up and down.
  • We can custom code it but it's not easy to provides a custom ui customization.
    • Until we find a way, we simply get all comments of the comments of the data and display it in list view.
  • And if you are building app with Flutter without FlutterFlow, we recommend you to use the SliverListView. And we encourage you to use Flutter (without FlutterFlow) if yo are good at source coding.

Terms

  • Root: An object that the comments belong to. It can be a user, photo, product item, blog/post, or whatever.
  • First level comments: are comments created directly under a Root.

Database Structure of Comment

Widgets

CommentInputBox

This is a simple comment create widget.

CommentInputBox(
  parent: comment,
),
SliverToBoxAdapter(
  child: CommentFakeInputBox(
    onTap: () => CommentService.instance.showCommentEditDialog(
      context: context,
      documentReference: ref,
      focusOnContent: true,
    ),
  ),
),

Displaying comments

The easy_comment provides two list view widgets for displaying comments.

You can copy the code from easy_comment and build your own comment list view widget for different UI/UX,

CommentListView

The first one is CommentListView. This is similar two ListView.

You can use CommentListView like below to display the comments.

CommentListView(
  documentReference: ref,
  shrinkWrap: true,
  physics: const NeverScrollableScrollPhysics(),
  itemBuilder: (comment, index) =>
      CommentListDetail(comment: comment),
),

For the itemBuilder, you may use one of CommentDetail, CommentListDetail, CommentListArrowDetail, or CommentListVerticalLineDetail. Or you can copy the code and build your own.

Example: Below is an example of using the available widgets.

CommentListView(
  documentReference: ref,
  itemBuilder: (comment, index) {
    return CommentListDetail(comment: comment); // default
    return CommentListArrowDetail(comment: comment); // arrow style comment
    return CommentListVerticalLineDetail(comment: comment); // vertical line comment
  },
),

CommentListTreeView

CommentListTreeView provides a nice tree style vertical lines on the nested comment list. It is designed to work in sliver scroll view. So, you should use CustomScrollView on the screen.

SliverToBoxAdapter(
  child: CommentFakeInputBox(
    onTap: () => CommentService.instance.showCommentEditDialog(
      context: context,
      documentReference: task.ref,
      focusOnContent: true,
    ),
  ),
),
CommentListTreeView(documentReference: task.ref),

onCreate CallBack

The onCreate is a callback after the comment is created. You can use this callback to do something comment post is created.

Usage: (e.g. send push notification to ancestor uid)

In the example below, we can send push notification to ancestor uid after the comment is created. It contains the newly created comment information.

First we get the ancestor uids after the comment is created, then we send a push notification to the ancestor uids.

    CommentService.instance.init(
      onCreate: (Comment comment) async {
        /// get ancestor uid
        List<String> ancestorUids =
            await CommentService.instance.getAncestorsUid(comment.id);
        /// get post information
        Post post = await Post.get(comment.documentReference.id);
        if (myUid != null && post.uid != myUid) {
          ancestorUids.add(post.uid);
        }

        if (ancestorUids.isEmpty) return;

        /// set push notification to remaining uids
        /// can get comment or post to send more informative push notification
        MessagingService.instance.sendMessageToUids(
          uids: ancestorUids,
          title: 'title ${DateTime.now()}',
          body: 'ancestorComment test ${comment.content}',
          data: {
            "action": 'comment',
            'commentId': comment.id,
            'postId': comment.documentReference.id,
          },
        );
      },
    );

Development Tips

Testing

import 'package:easy_comment/easy_comment.dart';
import 'package:easy_post_v2/easy_post_v2.dart';
import 'package:easyuser/easyuser.dart';
import 'package:flutter/material.dart';

class CommentTestScreen extends StatefulWidget {
  static const String routeName = '/CommentTest';
  const CommentTestScreen({super.key});

  @override
  State<CommentTestScreen> createState() => _CommentTestScreenState();
}

class _CommentTestScreenState extends State<CommentTestScreen> {
  @override
  Widget build(BuildContext context) {
    // final ref = my.ref;
    // final ref = Post.col.doc('1zsZ2YMplgZN6D6bdZIn');
    // final ref = Post.col.doc('0-console');
    // final ref = Post.col.doc('0-console-2');
    // final ref = Post.col.doc('0-con-3');
    // final ref = Post.col.doc('0-a');
    // final ref = Post.col.doc('0-b');
    // final ref = Post.col.doc('0-c');
    final ref = Post.col.doc('0-4');
    return Scaffold(
      appBar: AppBar(
        title: const Text('CommentTest'),
      ),
      body: Padding(
        padding: const EdgeInsets.fromLTRB(24.0, 24, 24, 0),
        child: MyDocReady(
          builder: () => ListView(
            padding: const EdgeInsets.all(0),
            children: [
              Text('Reference: ${ref.path}'),
              const SizedBox(height: 24),
              CommentFakeInputBox(
                onTap: () => CommentService.instance.showCommentEditDialog(
                  context: context,
                  documentReference: ref,
                  focusOnContent: true,
                ),
              ),
              CommentInputBox(
                documentReference: ref,
              ),
              CommentListView(
                documentReference: ref,
                shrinkWrap: true,
                physics: const NeverScrollableScrollPhysics(),
                itemBuilder: (comment, index) =>
                    CommentListArrowDetail(comment: comment),
              ),
            ],
          ),
        ),
      ),
      bottomNavigationBar: SafeArea(
        top: false,
        child: CommentFakeInputBox(
          onTap: () => CommentService.instance.showCommentEditDialog(
            context: context,
            documentReference: ref,
            focusOnContent: true,
          ),
        ),
      ),
    );
  }
}