Skip to content

feat: native pagination support (JetLimePaginatedColumn / JetLimePaginatedRow)#68

Merged
pushpalroy merged 3 commits into
mainfrom
proy/feat/pagination
Jun 14, 2026
Merged

feat: native pagination support (JetLimePaginatedColumn / JetLimePaginatedRow)#68
pushpalroy merged 3 commits into
mainfrom
proy/feat/pagination

Conversation

@pushpalroy

@pushpalroy pushpalroy commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Context

Resolves discussion #64 — a request for JetLime to manage pagination / infinite scroll internally so consumers don't have to wire up scroll detection themselves.

Implemented natively in Compose — no new dependency (JetLime stays dependency-light).

What's added

Two new, purely additive composables — JetLimePaginatedColumn and JetLimePaginatedRow:

  • Watch LazyListState.layoutInfo via derivedStateOf and fire onLoadMore when the user scrolls within loadMoreThreshold items of the end — guarded by !isLoading && hasMoreItems.
  • Render an optional loadingContent footer while isLoading (default: centered CircularProgressIndicator).
  • onLoadMore wrapped in rememberUpdatedState so the restarting effect always calls the latest lambda.
  • Page state (itemsList, isLoading, hasMoreItems) is owned by the caller.

The existing JetLimeColumn / JetLimeRow signatures are untouched → fully backward compatible.

Timeline-line continuity

EventPosition.dynamicPaginated(index, listSize, isLastPage) keeps the last loaded item as MIDDLE (not END) while more pages can load, so the connecting line flows continuously into the next page instead of flickering on each append. It resolves to END once hasMoreItems = false.

Changes

  • JetLimePaginatedList.kt (new) — the two composables + load-more trigger.
  • EventPosition.ktdynamicPaginated() factory.
  • JetLimeDefaults.ktLoadMoreThreshold (default 3).
  • Sample — new "Paginated" tab + PaginatedVerticalTimeLine screen (fake paged data source).
  • README — Pagination section + highlight.
  • TestsJetLimePaginatedColumnTest: display, loading footer, scroll trigger, hasMoreItems guard, and the connector-continuity logic.

Note: the first page must be triggered explicitly by the consumer — the scroll-based loader only fires once items exist. This is documented in the README and demonstrated in the sample.

Verification

  • spotlessCheck passes
  • :jetlime compiles for Android, Desktop, and common metadata
  • :sample:composeApp compiles
  • ⚠️ Instrumented tests compile, install, and run, but the suite currently can't pass on Android API 37 (beta) due to a pre-existing androidx.test/InputManager.getInstance incompatibility that affects all instrumented tests (not specific to this change). They should be run on a stable API (≤ 36) device/emulator.

…PaginatedRow)

Adds optional, dependency-free pagination (infinite scroll) for timelines,
resolving discussion #64. Two new composables fire an `onLoadMore` callback
when the user scrolls within `loadMoreThreshold` items of the end (guarded by
`isLoading`/`hasMoreItems`) and render an optional loading footer. The existing
JetLimeColumn/JetLimeRow are untouched (fully backward compatible).

- JetLimePaginatedList.kt: JetLimePaginatedColumn / JetLimePaginatedRow built on
  derivedStateOf over LazyListState + a rememberUpdatedState-guarded LaunchedEffect.
- EventPosition.dynamicPaginated(): keeps the last loaded item as MIDDLE while more
  pages can load so the connecting line stays continuous, terminating only on the
  last page.
- JetLimeDefaults.LoadMoreThreshold: default trigger distance.
- Sample: new "Paginated" tab + PaginatedVerticalTimeLine screen.
- README: Pagination section + highlight.
- Instrumented tests for display, loading footer, scroll trigger, guards, and the
  connector-continuity logic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: de596bf318

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread jetlime/src/commonMain/kotlin/com/pushpal/jetlime/EventPosition.kt Outdated
@pushpalroy pushpalroy self-assigned this Jun 14, 2026
@pushpalroy pushpalroy added the enhancement New feature or request label Jun 14, 2026
pushpalroy and others added 2 commits June 14, 2026 23:11
Make `loadingContent` nullable on JetLimePaginatedColumn / JetLimePaginatedRow.
It keeps the default centered progress indicator and remains fully customizable
via a slot, and passing `null` now cleanly omits the footer entirely (no empty
item is added to the lazy list). Documented the behavior and added tests for the
default loader, a custom loader, and the hidden (null) case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses Codex review on EventPosition.dynamicPaginated: when a paginated list
has exactly one loaded item and more pages remain, index 0 was returned as MIDDLE,
making isNotStart() true and drawing a spurious incoming connector before the first
event. Only the outgoing connector should be forced on while pages remain, so a
single-item pending list now stays START (isNotEnd() true, isNotStart() false).
Added a test for the single-item pending case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pushpalroy pushpalroy merged commit 21c281d into main Jun 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant