@Override
  void onNext(PostsWrapper data) {
    boolean pullUpToRefresh = isPullUpToRefresh();
    if (pullUpToRefresh) {
      // mRecyclerAdapter.getItemCount() = 0
      // when configuration changes (like orientation changes)
      if (mRecyclerAdapter.getItemCount() != 0) {
        mRecyclerAdapter.hideFooterProgress();
      }
    }

    Posts posts = data.getPosts();
    List<Post> postList = posts.getPostList();
    // if user has logged out, has no permission to access this thread or this thread is invalid
    if (postList.isEmpty()) {
      consumeResult(data.getResult());
    } else {
      super.onNext(data);

      int lastItemCount = mRecyclerAdapter.getItemCount();
      mRecyclerAdapter.setDataSet(postList);
      if (pullUpToRefresh) {
        int newItemCount = mRecyclerAdapter.getItemCount() - lastItemCount;
        if (newItemCount > 0) {
          mRecyclerAdapter.notifyItemRangeInserted(lastItemCount, newItemCount);
        }
      } else {
        mRecyclerAdapter.notifyDataSetChanged();

        String quotePostId = getArguments().getString(ARG_QUOTE_POST_ID);
        if (!TextUtils.isEmpty(quotePostId)) {
          for (int i = 0, length = postList.size(); i < length; i++) {
            if (quotePostId.equals(postList.get(i).getId())) {
              // scroll to quote post
              mRecyclerView.scrollToPosition(i);
              break;
            }
          }
          // clear this argument after redirecting
          getArguments().putString(ARG_QUOTE_POST_ID, null);
        }
      }

      Thread postListInfo = posts.getPostListInfo();
      // we have not title if we open thread link in our app
      if (getActivity().getTitle() == null) {
        mPagerCallback.setThreadTitle(postListInfo.getTitle());
      }
      mPagerCallback.setTotalPageByPosts(postListInfo.getReplies() + 1);
      if (posts.getThreadAttachment() != null) {
        mPagerCallback.setupThreadAttachment(posts.getThreadAttachment());
      }
    }
  }