6262import java9 .util .Objects ;
6363
6464public class MediaCommentsFragment extends Fragment {
65+ private static final int LAST_PAGE = -1 ;
6566 private static final String TAG = "MediaCommentsFragment" ;
6667 private final SingleViewAdapter .BindingSingleViewAdapter <LayoutLoadingBinding > loadingAdapter ;
6768 private final WeakHashMap <CatalogComment , Parcelable > scrollPositions = new WeakHashMap <>();
69+ private final WeakHashMap <CatalogComment , Integer > pages = new WeakHashMap <>();
6870 private final CommentsAdapter commentsAdapter = new CommentsAdapter ();
6971 private final List <CatalogComment > currentCommentsPath = new ArrayList <>();
7072 private final Runnable backPressCallback ;
73+ private boolean isLoading ;
7174 private ExtensionProvider selectedProvider ;
7275 private RecyclerView recycler ;
7376 private Runnable onCloseRequestListener ;
@@ -130,11 +133,11 @@ public void setMedia(CatalogMedia media) {
130133 this .media = media ;
131134 if (adapter == null ) return ;
132135
133- loadData (null , null );
136+ loadData (null , null , 0 );
134137 }
135138
136139 private void setComment (@ Nullable CatalogComment comment , CatalogComment reloadThis ) {
137- this .recycler .scrollToPosition (0 );
140+ // this.recycler.scrollToPosition(0);
138141 this .comment = comment ;
139142
140143 if (comment != null ) {
@@ -167,9 +170,13 @@ private void setComment(@Nullable CatalogComment comment, CatalogComment reloadT
167170 var layoutManager = requireNonNull (recycler .getLayoutManager ());
168171 layoutManager .onRestoreInstanceState (scrollPosition );
169172 }
173+
174+ if (comment != null && !comment .hasNextPage ()) {
175+ reachedEnd ();
176+ }
170177 }
171178
172- private void loadData (CatalogComment parent , CatalogComment reloadThis ) {
179+ private void loadData (CatalogComment parent , CatalogComment reloadThis , int page ) {
173180 if (this .comment != null ) {
174181 var layoutManager = requireNonNull (recycler .getLayoutManager ());
175182 scrollPositions .put (this .comment , layoutManager .onSaveInstanceState ());
@@ -199,16 +206,30 @@ private void loadData(CatalogComment parent, CatalogComment reloadThis) {
199206 }
200207
201208 var request = new ReadMediaCommentsRequest ()
202- .setPage (0 )
209+ .setPage (page )
203210 .setParentComment (parent )
204211 .setMedia (media );
205212
213+ isLoading = true ;
214+
206215 selectedProvider .readMediaComments (request , new ExtensionProvider .ResponseCallback <>() {
207216 @ Override
208- public void onSuccess (CatalogComment parent ) {
217+ public void onSuccess (CatalogComment newComment ) {
209218 runOnUiThread (() -> {
210219 if (getContext () == null ) return ;
211- setComment (parent , reloadThis );
220+ isLoading = false ;
221+
222+ if (page == 0 ) {
223+ pages .put (newComment , 0 );
224+ setComment (newComment , reloadThis );
225+ return ;
226+ }
227+
228+ commentsAdapter .addData (newComment );
229+
230+ if (!newComment .hasNextPage ()) {
231+ reachedEnd ();
232+ }
212233 }, recycler );
213234 }
214235
@@ -217,6 +238,7 @@ public void onFailure(Throwable e) {
217238 loadingAdapter .getBinding (binding -> runOnUiThread (() -> {
218239 if (getContext () == null ) return ;
219240 swipeRefresher .setRefreshing (false );
241+ isLoading = false ;
220242
221243 if (parent != null && (reloadThis == null ||
222244 (e instanceof JsException jsE && Objects .equals (jsE .getErrorId (), JsException .ERROR_NOTHING_FOUND )))) {
@@ -242,6 +264,18 @@ public void onFailure(Throwable e) {
242264 });
243265 }
244266
267+ private void reachedEnd () {
268+ pages .put (comment , LAST_PAGE );
269+
270+ loadingAdapter .getBinding (binding -> {
271+ binding .info .setVisibility (View .VISIBLE );
272+ binding .progressBar .setVisibility (View .GONE );
273+ binding .title .setText (R .string .you_reached_end );
274+ binding .message .setText (R .string .you_reached_end_description );
275+ loadingAdapter .setEnabled (true );
276+ });
277+ }
278+
245279 @ Override
246280 public void onViewCreated (@ NonNull View view , @ Nullable Bundle savedInstanceState ) {
247281 providers = stream (ExtensionsFactory .getExtensions (Extension .FLAG_WORKING ))
@@ -257,14 +291,21 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
257291 selectedProvider = providers .get (0 );
258292 }
259293
294+ recycler .addOnScrollListener (new RecyclerView .OnScrollListener () {
295+ @ Override
296+ public void onScrollStateChanged (@ NonNull RecyclerView recyclerView , int newState ) {
297+ tryLoadMore ();
298+ }
299+ });
300+
260301 setMedia (media );
261302 }
262303
263304 @ Nullable
264305 @ Override
265306 public View onCreateView (@ NonNull LayoutInflater inflater , @ Nullable ViewGroup container , @ Nullable Bundle savedInstanceState ) {
266307 swipeRefresher = new SwipeRefreshLayout (inflater .getContext ());
267- swipeRefresher .setOnRefreshListener (() -> loadData (comment , comment ));
308+ swipeRefresher .setOnRefreshListener (() -> loadData (comment , comment , 0 ));
268309
269310 var parentLayout = new LinearLayoutCompat (inflater .getContext ());
270311 parentLayout .setOrientation (LinearLayoutCompat .VERTICAL );
@@ -284,7 +325,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
284325
285326 adapter = new ConcatAdapter (new ConcatAdapter .Config .Builder ()
286327 .setStableIdMode (ConcatAdapter .Config .StableIdMode .ISOLATED_STABLE_IDS ).build (),
287- loadingAdapter , commentsAdapter );
328+ commentsAdapter , loadingAdapter );
288329
289330 recycler .setAdapter (adapter );
290331 parentLayout .addView (recycler , createLinearParams (MATCH_PARENT , 0 , 1 ));
@@ -318,7 +359,7 @@ public void onSuccess(CatalogComment comment) {
318359 /* So apparently people wanna to see all comments even after you did post a new one.
319360 Weird... */
320361 loadData (MediaCommentsFragment .this .comment ,
321- MediaCommentsFragment .this .comment );
362+ MediaCommentsFragment .this .comment , 0 );
322363
323364 sendBinding .loadingIndicator .setVisibility (View .GONE );
324365 sendBinding .sendButton .setVisibility (View .VISIBLE );
@@ -349,6 +390,25 @@ public void onFailure(Throwable e) {
349390 return swipeRefresher ;
350391 }
351392
393+ private void tryLoadMore () {
394+ if (media == null ) return ;
395+ var page = pages .get (comment );
396+
397+ if (page == null ) {
398+ throw new NullPointerException ("Page not found!" );
399+ }
400+
401+ if (!isLoading && page != LAST_PAGE ) {
402+ var lastIndex = comment .size () - 1 ;
403+
404+ if (recycler .getLayoutManager () instanceof LinearLayoutManager manager
405+ && manager .findLastVisibleItemPosition () >= lastIndex ) {
406+ pages .put (comment , page + 1 );
407+ loadData (comment , comment , page + 1 );
408+ }
409+ }
410+ }
411+
352412 private class CommentsAdapter extends RecyclerView .Adapter <CommentViewHolder > {
353413 private final UniqueIdGenerator idGenerator = new UniqueIdGenerator ();
354414 private CatalogComment root ;
@@ -373,6 +433,18 @@ public void setData(@Nullable CatalogComment root) {
373433 notifyDataSetChanged ();
374434 }
375435
436+ public void addData (@ Nullable CatalogComment root ) {
437+ if (root == null ) return ;
438+
439+ for (var item : root .items ) {
440+ item .visualId = idGenerator .getLong ();
441+ }
442+
443+ var wasSize = comment .size ();
444+ this .root .items .addAll (root .items );
445+ notifyItemRangeInserted (wasSize , root .items .size ());
446+ }
447+
376448 @ NonNull
377449 @ Override
378450 public CommentViewHolder onCreateViewHolder (@ NonNull ViewGroup parent , int viewType ) {
@@ -384,7 +456,7 @@ public CommentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewT
384456 var comment = holder .getComment ();
385457 if (comment == MediaCommentsFragment .this .comment ) return ;
386458
387- loadData (comment , null );
459+ loadData (comment , null , 0 );
388460 });
389461
390462 return holder ;
0 commit comments