vc=90: cold-start store hydration off-Main + video-page status-bar fix + RYD FFI slim
Resume + Enrichment stores no longer JSON-decode on the main thread in Application.onCreate (Resume is the heaviest cold-start cost: ~50-100ms decode at its 100k-entry cap). Both seed an empty StateFlow and hydrate off-thread on their PrefsWriter single-thread dispatcher. Mutations that arrive before the hydrate finishes defer onto that FIFO dispatcher (a hydrated gate) so they re-run on fully-loaded state -- correct for adds AND clears; a naive loaded+live merge would resurrect a clear that landed on the empty seed. Subscriptions/Playlists/History/Settings stay eager (tiny + rendered directly -> would flash empty). (audit 2.1) Video page: details/related rows no longer leak into the status-bar strip above the player when scrolled. topPadding is now a layout inset on the detail LazyColumn, so the scroll viewport begins+clips at the player's bottom edge instead of letting rows scroll up over the clock/signal. RYD: dropped the dead rating + view_count fields from the strawcore RydVotes FFI Record + Kotlin shim -- only likes/dislikes are rendered; RYD's rating restates the like/dislike ratio and its viewCount is a stale aggregate conflicting with the real YouTube count already shown. (audit #2 L-9) Adversarially reviewed (Opus): clear-resurrection closed, no defer-loop, FFI slim has no readers. Headless compileDebugKotlin green.
This commit is contained in:
parent
93bf86f534
commit
1e89c0739a
7 changed files with 150 additions and 25 deletions
|
|
@ -91,31 +91,32 @@ pub(crate) async fn read_capped_body(resp: reqwest::Response, cap: usize) -> Opt
|
|||
|
||||
/// Vote counts from the Return-YouTube-Dislike API. Kotlin maps this onto
|
||||
/// its own `net.RydVotes` data class (the detail-screen overlay model).
|
||||
///
|
||||
/// We carry only the fields the UI actually renders (likes/dislikes). RYD's
|
||||
/// own `rating` (a 0-5 restatement of the like/dislike ratio) and `viewCount`
|
||||
/// (RYD's stale aggregate — the real YouTube count from `videoDetails` is what
|
||||
/// the detail screen already shows) are intentionally NOT surfaced: rendering
|
||||
/// either would be redundant or actively misleading, so they don't cross the
|
||||
/// FFI (audit #2 L-9 — slimmed the dead carry-through).
|
||||
#[derive(Debug, Clone, uniffi::Record)]
|
||||
pub struct RydVotes {
|
||||
pub id: String,
|
||||
pub likes: i64,
|
||||
pub dislikes: i64,
|
||||
pub rating: f64,
|
||||
pub view_count: i64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RydVotesWire {
|
||||
// `id` is required (no default) to match the Kotlin original, whose
|
||||
// non-nullable `id: String` made a response missing `id` fail to parse
|
||||
// and return null. likes/dislikes/rating/viewCount keep defaults — the
|
||||
// Kotlin data class defaulted those.
|
||||
// and return null. likes/dislikes keep defaults — the Kotlin data class
|
||||
// defaulted those. The JSON's `rating`/`viewCount` are simply not read
|
||||
// (serde ignores unknown fields here) — see RydVotes above.
|
||||
id: String,
|
||||
#[serde(default)]
|
||||
likes: i64,
|
||||
#[serde(default)]
|
||||
dislikes: i64,
|
||||
#[serde(default)]
|
||||
rating: f64,
|
||||
#[serde(default)]
|
||||
#[serde(rename = "viewCount")]
|
||||
view_count: i64,
|
||||
}
|
||||
|
||||
/// GET https://returnyoutubedislikeapi.com/votes?videoId=<id>
|
||||
|
|
@ -143,8 +144,6 @@ pub async fn fetch_ryd_votes(video_id: String) -> Option<RydVotes> {
|
|||
id: wire.id,
|
||||
likes: wire.likes,
|
||||
dislikes: wire.dislikes,
|
||||
rating: wire.rating,
|
||||
view_count: wire.view_count,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue