Skip to content

refactor(home): restructure the feed pipeline, fix pagination stalls, and add a cards-per-row setting - #1040

Merged
A-EDev merged 7 commits into
mainfrom
refactor/home-view-model
Sep 8, 2026
Merged

A-EDev merged 7 commits into
mainfrom
refactor/home-view-model

Conversation

@A-EDev

@A-EDev A-EDev commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Summary

Splits the 2,166-line home view model and the 651-line screen into focused files, moves the feed's pure logic out where it can be tested, and puts seed and related-graph retrieval behind an injected collaborator. On top of that it fixes the feed silently refusing to paginate, and adds a cards-per-row setting for the home grid.

Related issue

Closes #765
Closes #855
Closes #925

Change type

  • Bug fix
  • Feature
  • Refactor or maintenance
  • Build, packaging, or CI
  • Documentation

Validation

  • ./gradlew :app:assembleGithubDebug
  • ./gradlew :app:testGithubDebugUnitTest
  • I ran any additional flavor-specific build or test tasks affected by this change.
  • I manually tested the affected behavior on an Android device or emulator.

Also run and passing: ./gradlew spotlessCheck, :app:compileGithubDebugKotlin, :app:compileFossDebugKotlin.

Test device and Android version: Xiaomi POCO X6 Pro, HyperOS 3.0.9.0, Android 16

The refactor commits are intended to be output-identical; the two visual changes and the two
behaviour changes are called out below. No performance claim is made anywhere in this PR — the
structural changes were not profiled.

Screenshots or recordings

Risk and compatibility

Fixes

  • Homefeed scroll bug #765 — the home feed stopped paginating and only recovered if you scrolled up and back down.
    A load-more page that appended nothing (every candidate already on screen) set allowRestart = false
    and gave up. Nothing was appended, so the feed length was unchanged, so the last-visible index
    could not change, so the index-only viewport flow had nothing to re-emit — the queue could never
    re-arm. hasMorePages is never set false on the Flow-feed path either, so the end-of-feed footer
    did not show: the page just ended silently. Two fixes: an empty page now retries up to 3 times
    with backoff (each attempt advances the discovery-query cursor and rotates seeds, so it asks for
    different content), and the viewport flow now emits on isScrollInProgress as well as the index,
    so a further scroll attempt re-arms it.
  • [Feature]: Home Layout in Multiple Grid mode #855 / [Feature]: Flow UI #925 — no way to get more than one card per row. New Cards per row setting
    (Auto / 1 / 2 / 3) under Settings → Content display → Home layout, shown only in Grid mode since
    List is one per row by definition. Auto is the default and keeps today's behaviour.
  • A large-screen breakpoint gap. A ~600dp screen fell into the <700dp bucket and got a single
    full-width poster. Auto now gives 2 columns from 600dp up; below 600dp and every wider breakpoint
    are unchanged.
  • A per-item LaunchedEffect in the feed grid called enrichChannelMetadataIfMissing(videoId),
    whose first line was a linear scan of the whole video list — re-running for every item on every
    scroll recycle. It now takes the Video the call site already holds.
  • The feed item block was written twice (once before the shelves, once after) and the second copy
    had silently lost its home_video_card test tag, so instrumentation only ever saw the first
    1–4 cards.
  • Dead code in FlowNavigation: an inlinePlayerHeight that read two per-frame player animation
    values and was never used anywhere.
  • A redundant second viewModel.initialize(context) in HomeScreenFlowApp already calls it
    with the application context before the NavHost composes.

Behaviour changes worth knowing about

  • uiState moved from SharingStarted.Eagerly to WhileSubscribed(5_000). The dedup pass over
    the feed no longer runs on every background append while Home is off-screen.
  • Seed building no longer races app start. The view model held two fields pointing at the same
    ViewHistory singleton — a lazy one and a nullable one set in initialize(). Seed building used
    the nullable one and returned an empty list when it was still null, which on a cold start could
    leave the related lane empty because init starts loadFlowFeed before FlowApp calls
    initialize(). With constructor injection it is never null, so cold-start related seeds now
    populate.
  • The Shorts shelf position rounds up to a multiple of the column count. It spans every column,
    so at 3 columns the old fixed index would have started it after one card and left holes in the row
    above. Unchanged at every Auto breakpoint (1 / 2 / 3 / 4).
  • Two shared state components adopted on HomeFlowEmptyState for the feed-disabled state and
    FlowErrorState for the error state. These look different from the local versions they replace:
    a larger icon container, bodyLarge title, and a filled button instead of a text button. The
    retry label is unchanged (retry and action_retry are both "Retry").
  • The load-more spinner uses the existing shared FlowFeedProgress instead of a bare
    CircularProgressIndicator.
  • ContinueWatchingShelf moved out of ui/components/VideoCard.kt into a new
    ui/components/home/, along with its two private helpers. It had exactly one consumer.
  • Color.Red in the Shorts shelf is now a named theme token wired to the existing YouTubeRed
    literal. Color.Red is 0xFFFF0000, so this is pixel-identical.
  • New HomeFeedCacheRepository Hilt provider, matching the existing @Provides @Singleton
    delegate pattern. Four getInstance() / manual-construction sites in the view model are gone;
    instance identity is preserved.
  • New preference home_feed_columns, default AUTO. DataStore only — no Room schema change.
  • 3 new strings in values/strings.xml. Other locales are left to Weblate.
  • The Continue Watching tap builds its Video with a local helper rather than the shared
    VideoHistoryEntry.toVideo() mapper: that one carries isShort, which FlowNavigation branches
    on, so reusing it would have rerouted a resumed short to the Shorts player.

Known limitation

HomeViewModel.kt is 2,166 → ~1,270 lines, still over the 600-line ceiling. Everything that
separates cleanly has been extracted; what remains is one responsibility — loading and paging the
feed. Splitting it further would put the shared discovery-query cursor (discoveryQueries +
currentQueryIndex, advanced by wave 1, wave 2 and load-more alike) across a class boundary, which
is worse than a long file. Moving that cursor into its own owner is the honest prerequisite and is
left for a follow-up.

The cards-per-row setting is scoped to the home feed, so at 600–700dp Home shows 2 columns while
Subscriptions still shows 1. Extending it is a follow-up.

  • The change does not introduce secrets, private data, or unexpected telemetry.
  • New user-facing text uses Android string resources.
  • Dependency and lockfile changes are intentional and limited to this PR.
  • Room schema changes include the required version bump and migration, or this PR does not change the Room schema.
  • Breaking changes and upgrade steps are clearly documented.

Copilot AI lite review requested due to automatic review settings September 8, 2026 13:27

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the ui Compose UI, theming, or Material 3 surfaces label Sep 8, 2026
@A-EDev
A-EDev merged commit 452c296 into main Sep 8, 2026
5 checks passed
@A-EDev A-EDev added the merged Pull request verified, tested and merged label Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged Pull request verified, tested and merged ui Compose UI, theming, or Material 3 surfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Flow UI [Feature]: Home Layout in Multiple Grid mode Homefeed scroll bug

2 participants