Skip to content

Adds option to enable/disable infinite scroll - #2172

Draft
rodrigo-fm wants to merge 25 commits into
LemmyNet:mainfrom
rodrigo-fm:feature/toggle-pagination
Draft

Adds option to enable/disable infinite scroll#2172
rodrigo-fm wants to merge 25 commits into
LemmyNet:mainfrom
rodrigo-fm:feature/toggle-pagination

Conversation

@rodrigo-fm

@rodrigo-fm rodrigo-fm commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Here are a few pictures of the navigation without infinite scroll

image image image image image

And here's a video :)

scroll.mp4

Rodrigo Martins and others added 19 commits July 3, 2026 16:17
Currently translated at 100.0% (510 of 510 strings)

Translation: Lemmy/jerboa
Translate-URL: http://weblate.join-lemmy.org/projects/lemmy/jerboa/bg/
Currently translated at 43.1% (220 of 510 strings)

Translation: Lemmy/jerboa
Translate-URL: http://weblate.join-lemmy.org/projects/lemmy/jerboa/de/
Currently translated at 43.5% (222 of 510 strings)

Translation: Lemmy/jerboa
Translate-URL: http://weblate.join-lemmy.org/projects/lemmy/jerboa/de/
* Implement view pooling for AndroidViews

* Fix lint

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
…emmyNet#2162)

* Fix scroll stuck/glitchy in comments when scrolling up to an image

* Remove postId from CommentBody cacheKey

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
…ing to the top of the screen after loading posts.
Comment thread app/src/main/java/com/jerboa/db/entity/AppSettings.kt Outdated
var nextPageCursor: PaginationCursor? = null
var page by mutableLongStateOf(1)

fun appendPage(nextPage: PaginationCursor?) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be a dupe of nextPage but without pushing to the stack. Why is that necessary?

val previousPageCursors = Stack<PaginationCursor?>()
var currentPageCursor: PaginationCursor? = null
var nextPageCursor: PaginationCursor? = null
var page by mutableLongStateOf(1)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this need to change. I thought mutableStateOf only matter for functional components.


class PaginationController {

val previousPageCursors = Stack<PaginationCursor?>()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 1.0, we won't need this stack, as the PagedResponse returns a prev_page and next_page, so please add a TODO comment about that.

Comment thread app/src/main/java/com/jerboa/feed/PaginationController.kt
Comment thread app/src/main/java/com/jerboa/ui/components/common/Buttons.kt Outdated
Comment on lines +40 to +42
onNext: () -> Unit,
onPrevious: () -> Unit,
onNextEnabled: Boolean = true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define this sealed class to help with page types:

sealed class PageType {
    data class Number(val data: Long) : PageType
    data class Cursor(val data: PaginationCursor) : PageType
}

In anticipation of 1.0, provide it with 3 things.

current: PageType?,
nextPage: PageType?,
prevPage: PageType?,

Then do

onNext: (PageType) -> Unit,
onPrev: (PageType) -> Unit,

You can remove onNextEnabled because you'll know this from giving it the nextPage

onNextPage = {
personProfileViewModel.navigatePagination(profileId, 1)
},
onPreviousPage = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll now be able to use the correct cursor from the on page button click

@Composable
fun PostListings(
posts: List<PostView>,
posts: List<PostView>?,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just show the message for an empty list, which is what's returned by the api anyway. No need for an option.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this to avoid showing "No more posts available" while loading the posts, I thought this could be seen as a bug by some users. This implementation allowed me to show the "No more posts available" only when the response returns an empty list of posts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while loading the posts

The screen above this shouldn't load this component until its ApiState == success, so loading should already be handled. IE the screen should have a ApiState == Loading indicator, that prevents even rendering the PostListings component otherwise.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if I understood it correctly, but the HomeActivity loads the composable like this on the main branch:

val posts: List<PostView> = when (val postsRes = homeViewModel.postsRes) {
    is ApiState.Failure -> {
        apiErrorToast(ctx, postsRes.msg)
        listOf()
    }

    is ApiState.Holder -> {
        postsRes.data
    }

    else -> {
        listOf()
    }
}

The else branch is triggered when postRes is ApiState.Loading, so the message "No more posts available" is displayed while loading because the list is empty. Changing the argument type to List<PostView>? was the easiest way I found to avoid displaying the message while loading the posts.

The CommunityScreen does it differently, though. It only loads the PostListings composable when postRes is ApiState.Holder. I can apply this logic on the HomeActivity, you want it to be like that?

CommunityScreen example:

when (val postsRes = communityViewModel.postsRes) {
  ApiState.Empty -> {
      ApiEmptyText()
  }
  
  is ApiState.Failure -> {
      ApiErrorText(postsRes.msg)
  }
  
  is ApiState.Holder -> { /* load composable */ }

@rodrigo-fm

rodrigo-fm commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Hi, thanks for the comments. I'm currently looking into moving the logic from LookAndFeelScreen to AccountSettings, I currently don't have much time, but I'm trying to code this feature every day, even if it's for a few minutes, so I'll probably take more than a week to catch up with all the changes.

@dessalines

Copy link
Copy Markdown
Member

No problem. Its going to take me a long time to get the 1_0_dev branch up to shape anyway, and that's where I'll probably have to merge this to.

@dessalines dessalines left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still some unaddressed comments from the last review.

Mark the PR as draft, then ready for review when you're ready for us again.

Comment thread app/src/main/java/com/jerboa/db/entity/Account.kt
swipeToActionPreset = swipeToActionPreset,
)
item {
if (enableInfiniteScroll) Spacer(modifier = Modifier.height(100.dp))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This size needs to be defined somewhere, and it should be part of the paginator row margins.

}
item {
if (!enableInfiniteScroll) {
PaginationButton(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure I have a comment in the last review about renaming this.

@rodrigo-fm
rodrigo-fm marked this pull request as draft July 23, 2026 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants