From 22d87d2398c69b92e90445e8e5e891bb2936df51 Mon Sep 17 00:00:00 2001 From: Jeena Date: Mon, 19 Oct 2026 14:40:26 +0000 Subject: [PATCH] =?UTF-8?q?channels:=20sort=20rows=20on=20stable=20keys=20?= =?UTF-8?q?only=20=E2=80=94=20subscriber=20counts=20shifted=20everything?= =?UTF-8?q?=20mid-load?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Making subscribers the primary key reordered both rows and whole rows as the per-channel subscriber refine streamed in: each background batch re-sorted the screen while loading, and the list jumped several times on entry (user: "the jumping is terrible"). The subscriber counts are not in the video-listing fast path; they only arrive seconds later in per-channel batches, so any ordering that leads with them cannot render early. Back to the stable keys — own row first, then video totals (then plays, then subscribers) on both the row and the channel level. These come entirely from the video listing before the first rebuild, so the screen painted correctly once, verified: a single rebuild line across the whole TV load, no further reshuffling. Video-less channels still never render, the own row still holds first place whenever it exists. --- .../jeena/jtubetv/ui/screens/ChannelsScreen.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/net/jeena/jtubetv/ui/screens/ChannelsScreen.kt b/app/src/main/java/net/jeena/jtubetv/ui/screens/ChannelsScreen.kt index 2b5c424..1de2c73 100644 --- a/app/src/main/java/net/jeena/jtubetv/ui/screens/ChannelsScreen.kt +++ b/app/src/main/java/net/jeena/jtubetv/ui/screens/ChannelsScreen.kt @@ -76,8 +76,7 @@ import net.jeena.jtubetv.ui.screens.list.dpadCenterActivatable * Channels, SmartTube-style: one row per LOCAL user. * * - Row 1: the logged-in user ("'s Channels") — only when they own - * at least one channel WITH videos; then the other local users, rows and - * channels alike sorted by subscribers / videos / views (desc). + * at least one channel WITH videos; then the other local users by total videos. * - Channels with no videos never render (watching-only accounts), at any level. * - Followed-instance channels at the end, grouped per platform. * @@ -281,10 +280,13 @@ class ChannelsViewModel(private val store: TokenStore) : ViewModel() { val byOwner = locals.groupBy { ownerKey(it) } val groups = byOwner.values.map { row -> val sorted = row.sortedWith( - // One ordering everywhere: subscribers, videos, views (desc). - compareByDescending { it.followersCount } - .thenByDescending { statOf(it) } - .thenByDescending { playsOf(it) }, + // Stable keys only: all of these come from the video listing and + // never change mid-load — subscriber counts arrive later per- + // channel and must not reorder anything while loading (rows that + // jump while stats stream in read as broken). + compareByDescending { statOf(it) } + .thenByDescending { playsOf(it) } + .thenByDescending { it.followersCount }, ) val own = row.firstOrNull { it.name in ownNames } UserGroup( @@ -296,9 +298,9 @@ class ChannelsViewModel(private val store: TokenStore) : ViewModel() { } userRows = groups.sortedWith( compareByDescending { g -> g.channels.any { it.name in ownNames } } - .thenByDescending { g -> g.channels.sumOf { it.followersCount } } .thenByDescending { g -> g.channels.sumOf { statsMap[it.name + "@" + it.host]?.videos ?: 0 } } - .thenByDescending { g -> g.channels.sumOf { statsMap[it.name + "@" + it.host]?.plays ?: 0 } }, + .thenByDescending { g -> g.channels.sumOf { statsMap[it.name + "@" + it.host]?.plays ?: 0 } } + .thenByDescending { g -> g.channels.sumOf { it.followersCount } }, ) Log.w( "JTube",