Skip to content
JaeHo Song edited this page Sep 17, 2022 · 11 revisions

FireFlutter

The simplest Firebase and Flutter framework for building social apps, shopping apps, CMS(content management system) apps, and more.

Test

  • To run the test, $ cd firebase/functions && npm run test <test-script-path>.

    • i.e) $ npm run test tests/point/time-passed.spect.ts
  • To run the test on firebase test project, use test credentials in firebase-app-initialize.ts.

User settings

  • User settings are saved under user document. /users/<uid>/user_settings/<docId> {...}.
  • User's common settings are saved in /users/<uid>/user_settings/settings document.
    • Use MySettingsDoc to build and display widgets based on the settings value.
    • Since MySettingsDoc is reactive, you don't need a state management or to call setState().
MySettingsDoc(builder: (settings) {
  return SwitchListTile(
    title: Text('Notify new comments under my posts and comments'),
    value: settings[commentNotification] ?? false,
    onChanged: ((value) async {
      await updateMySettings({commentNotification: value});
    }),
  );
});
  • Updating(Creating) a user setting document and deleting it.
    • This example code enables or disables messaging notifications with CheckboxListTile widget.
@override
Widget build(BuildContext context) {
  String id = '$type-create.${category.id}';
  return MySettingsDoc(
    id: id,
    builder: (settings) {
      return CheckboxListTile(
        value: settings == null ? false : true,
        onChanged: ((value) async {
          if (value == true) {
            await updateMySettings(id: id, {
              'action': '$type-create',
              'category': category.id,
            });
          } else {
            await deleteMySettings(id);
          }
        }),
        title: Text(category.title),
      );
    },
  );
}
  • This is the sample screen of the code above.

Push messaging settings screen

  • This is the firestore doucment for the actions of the code above.

Firestore messaging subscriptions

  • You can pass the setting's document id to MySettingsDoc to oberve different settings document under /users/<uid>/user_settings collection.

  • Use mySettings(uid) in FireFlutterMixin to get the user's settings.

Push Messaging

  • Push message subscriptions for each forum category are saved in user's setting collection.

    • /users/<uid>/user_settings/{subscriptionDocumentId} {action: comment-create, category: qna}
      • One thing to note, the field name must be unique due to the limit of 200 Firestore query index. So, a field name should not be like {comment-create.qna: true}. It should be like separated as action and category.
      • But subscriptionDocumentId can be a unique document id like comment-create.qna, post-create.discussion.
        • Be careful not to save any document which has action and category on other setting docuement aside from the subscription settings document. It would work if the action field does not contain post-create or comment-create thought.
      • So, the subscription document would be /users/<uid>/user_settings/comment-create.qna {action: comment-create, category: qna}.
      • if {action: comment-create, category: qna} is set, there will be a new message on a new comment in qna category.
      • if {action: post-create, category: discussion} is set, then there will be a messgae on new post on discussion category.
  • User options for receiving all the comments under the user's posts or comments is saved like below

    • /users/<uid>/user_settings/settings {notify-new-comment-under-my-posts-and-comments: true}
  • FireFlutter does not send message with topics. It only sends message with tokens.

    • If you need to send a message to all users(to all tokens), then use Cloud Messaging in Firebase Console.
  • /users/<uid>/fcm_tokens/<docId> {uid: ..., token: ...}

  • Push message works with PostModel and CommentModel.

    • When a new post is created, PostModel.create() will be invoked and push message is sent there.

Point and level

  • FireFlutter supports point system. When a user creates a post or comment, the user will get point randomly. And the system give a level to the user based on the point that user earned.

  • User point will be saved under /user/<uid>/user_meta/point {...} and that is read only. FireFlutter will observe this doc and update the point in it.

  • User point and its history will be saved under /user/<uid>/point_history/<pointHistoryId> {...}.

  • Admin can set maximum point on each category. Admin may set the value to 0 not to give point on that category. For instance, admin may set point to 0 to a greeting category if he wouldn't want to give any point to users when they say 'hi' only. The posts on greeting category are more on meaningless and users are tempting to abuse the system to get more point.

  • When a user creates a post,

    • clould function will increase point and leave history if the within time passed. If within time didn't pass, then there will be no more point increasement.
    • the amount of the point will be randomly generaged with the maxium value of the category.point if the category has value.
      • If category.point is 0, the user will not get any point on that category.
    • The total point is saved(updated) in /users/<uid>/user_meta/point
    • And the point history will be added under /users/<uid>/point_history/<pointHistoryDocId>
    • And the point for the post creation will be updated on the post. So, it can be displayed on post view screen.
  • When a user create a comment, the logic is almost the same as post.

    • One thing to note is that, the maximum point of comment creation is 30 and it is hard-set in the source code. This is because there is no point setting for comment creation in category. If it has, then on comment creation, it can look for postId and its category setting. This may be available on next version.
      • Since the maximum point of comment creation is hard-coded, no need to change any thing on category settings. it will simply work.

Common Fitfalls

  • If the point is not increasing, see if the category has point.
    • The commnet creation point is automatially increasing without doing anything since it is hard-cordded. But for post creation point, the admin must set it on categroy settings.

Push notification

push notification queue

  • To send a push notification, there are two ways right now.

    • One is using Call function via client app and the other is adding a document in /push-notification-queue.
  • When the client app create a document with the following data format in the /push-notification-queue, The backgrond function will be trigger to send push notification.

Example of notification document)

{
  "createdAt": ...,
  "uids": [ ... ],
  "tokens": [ ... ],
  "title": ...,
  "body": ...,
  "senderUid": ...,
  "type": message type like 'post', 'chat', 'party', 'etc'.
  "id": "the target document id of the type. for instance, post id, chat user uid, etc.. to open the screen when user tap on message."
}
  • After the background function send push notifications, there will be some additional fields to be attached like below.
{
  "status": "success|failure",
  "succes": 38,
  "error": 4,
  "sentAt": "server Timestamp"
}
  • This is for sending push notifications only. There should not be any logic for other functionality.
    • For instance, user A can mute on user B's chat. When user A send a chat messages to user B, the app must not send push notification to user B and the logic must be in chat service. Not in this logic of push notification queue.

Category

Category.loadCategories

Loads categories and return them as in List of Category model.

You can filter some categories by [categoryGroup].

Category.getCategories

Returns all categories.

It does memory cache.

Note if categoris are not fetched from firestore, then it will fetch and return categories. Note if categories are already fetched, then it will return memory cached categories, instead of fetcing again.

If hideHiddenCategory is set to true, then it will not return categories whose order is -1.

Note that, this is async call. So, it should be used with setState