mirror of
https://github.com/FluxaMedia/fluxa-core.git
synced 2026-08-09 16:37:31 +00:00
Add pagination support for discover catalog browsing
Discover only ever fetched the first page (typically 20-50 items) of a catalog and had no way to request more. Add a discoverPageRequested action, a fetchDiscoverPage effect, and a dedicated DiscoverPaging generation key so an in-flight "load more" fetch can't clobber a fresh query (or vice versa) when the user changes catalog/genre mid-fetch.
This commit is contained in:
parent
323b46d9ae
commit
24a0e0dcb2
5 changed files with 96 additions and 1 deletions
|
|
@ -235,6 +235,14 @@ pub(super) enum AppAction {
|
|||
profile: Option<Value>,
|
||||
language: Option<String>,
|
||||
},
|
||||
#[serde(rename = "discoverPageRequested")]
|
||||
DiscoverPageRequested {
|
||||
transport_url: Option<String>,
|
||||
content_type: String,
|
||||
catalog_id: String,
|
||||
skip: Option<i32>,
|
||||
genre: Option<String>,
|
||||
},
|
||||
#[serde(rename = "catalogPageRequested")]
|
||||
CatalogPageRequested {
|
||||
category_id: String,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,25 @@ pub(super) struct DiscoverState {
|
|||
genres: Value,
|
||||
error: Value,
|
||||
generation: u64,
|
||||
paging: DiscoverPaging,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase", default)]
|
||||
pub(super) struct DiscoverPaging {
|
||||
is_loading: bool,
|
||||
items: Value,
|
||||
error: Value,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct FetchDiscoverPagePayload {
|
||||
transport_url: Option<String>,
|
||||
content_type: String,
|
||||
catalog_id: String,
|
||||
skip: i32,
|
||||
genre: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
@ -48,6 +67,7 @@ pub(super) fn dispatch_discover(
|
|||
language: Option<String>,
|
||||
) -> Vec<EffectEnvelope> {
|
||||
let generation = engine.bump_generation(GenerationKey::Discover);
|
||||
engine.bump_generation(GenerationKey::DiscoverPaging);
|
||||
let profile_value = profile.unwrap_or_else(|| engine.state.profile.active.clone());
|
||||
let profile_id = active_profile_id(&engine.state, &profile_value);
|
||||
let filters_value = filters.unwrap_or(Value::Null);
|
||||
|
|
@ -62,6 +82,7 @@ pub(super) fn dispatch_discover(
|
|||
genres: engine.state.discover.genres.clone(),
|
||||
error: Value::Null,
|
||||
generation,
|
||||
paging: DiscoverPaging::default(),
|
||||
};
|
||||
vec![engine.effect(
|
||||
EffectKind::RunDiscover,
|
||||
|
|
@ -102,6 +123,33 @@ pub(super) fn dispatch_catalog_filters(
|
|||
)]
|
||||
}
|
||||
|
||||
pub(super) fn dispatch_discover_page(
|
||||
engine: &mut HeadlessEngine,
|
||||
transport_url: Option<String>,
|
||||
content_type: String,
|
||||
catalog_id: String,
|
||||
skip: Option<i32>,
|
||||
genre: Option<String>,
|
||||
) -> Vec<EffectEnvelope> {
|
||||
let generation = engine.bump_generation(GenerationKey::DiscoverPaging);
|
||||
engine.state.discover.paging = DiscoverPaging {
|
||||
is_loading: true,
|
||||
items: Value::Null,
|
||||
error: Value::Null,
|
||||
};
|
||||
vec![engine.effect(
|
||||
EffectKind::FetchDiscoverPage,
|
||||
generation,
|
||||
FetchDiscoverPagePayload {
|
||||
transport_url,
|
||||
content_type,
|
||||
catalog_id,
|
||||
skip: skip.unwrap_or(0).max(0),
|
||||
genre,
|
||||
},
|
||||
)]
|
||||
}
|
||||
|
||||
pub(super) fn complete(
|
||||
engine: &mut HeadlessEngine,
|
||||
effect_type: &str,
|
||||
|
|
@ -149,6 +197,21 @@ pub(super) fn complete(
|
|||
}
|
||||
}
|
||||
}
|
||||
"fetchDiscoverPage" => {
|
||||
if generation == engine.state.runtime.get(GenerationKey::DiscoverPaging) {
|
||||
engine.state.discover.paging.is_loading = false;
|
||||
if result.status.is_ok() {
|
||||
engine.state.discover.paging.items = result
|
||||
.value
|
||||
.get("items")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| serde_json::json!([]));
|
||||
engine.state.discover.paging.error = Value::Null;
|
||||
} else {
|
||||
engine.state.discover.paging.error = normalize_error(result.error.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
vec![]
|
||||
|
|
|
|||
|
|
@ -442,6 +442,20 @@ impl HeadlessEngine {
|
|||
profile,
|
||||
language,
|
||||
),
|
||||
AppAction::DiscoverPageRequested {
|
||||
transport_url,
|
||||
content_type,
|
||||
catalog_id,
|
||||
skip,
|
||||
genre,
|
||||
} => discover::dispatch_discover_page(
|
||||
self,
|
||||
transport_url,
|
||||
content_type,
|
||||
catalog_id,
|
||||
skip,
|
||||
genre,
|
||||
),
|
||||
AppAction::CatalogPageRequested {
|
||||
category_id,
|
||||
transport_url,
|
||||
|
|
@ -605,7 +619,9 @@ impl HeadlessEngine {
|
|||
|
||||
EffectKind::RunSearch => search::complete(self, generation, &result),
|
||||
|
||||
EffectKind::RunDiscover | EffectKind::ReadDiscoverCatalogFilters => {
|
||||
EffectKind::RunDiscover
|
||||
| EffectKind::ReadDiscoverCatalogFilters
|
||||
| EffectKind::FetchDiscoverPage => {
|
||||
discover::complete(self, effect_type, generation, &result)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ pub(super) enum GenerationKey {
|
|||
Addon,
|
||||
Search,
|
||||
Discover,
|
||||
DiscoverPaging,
|
||||
Sync,
|
||||
Auth,
|
||||
Settings,
|
||||
|
|
@ -110,6 +111,7 @@ pub(super) struct RuntimeGenerations {
|
|||
addon_generation: u64,
|
||||
search_generation: u64,
|
||||
discover_generation: u64,
|
||||
discover_paging_generation: u64,
|
||||
sync_generation: u64,
|
||||
auth_generation: u64,
|
||||
settings_generation: u64,
|
||||
|
|
@ -131,6 +133,7 @@ impl RuntimeGenerations {
|
|||
GenerationKey::Addon => self.addon_generation,
|
||||
GenerationKey::Search => self.search_generation,
|
||||
GenerationKey::Discover => self.discover_generation,
|
||||
GenerationKey::DiscoverPaging => self.discover_paging_generation,
|
||||
GenerationKey::Sync => self.sync_generation,
|
||||
GenerationKey::Auth => self.auth_generation,
|
||||
GenerationKey::Settings => self.settings_generation,
|
||||
|
|
@ -152,6 +155,7 @@ impl RuntimeGenerations {
|
|||
GenerationKey::Addon => &mut self.addon_generation,
|
||||
GenerationKey::Search => &mut self.search_generation,
|
||||
GenerationKey::Discover => &mut self.discover_generation,
|
||||
GenerationKey::DiscoverPaging => &mut self.discover_paging_generation,
|
||||
GenerationKey::Sync => &mut self.sync_generation,
|
||||
GenerationKey::Auth => &mut self.auth_generation,
|
||||
GenerationKey::Settings => &mut self.settings_generation,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub enum EffectKind {
|
|||
FetchAddonManifest,
|
||||
FetchAddonResource,
|
||||
FetchCatalogPage,
|
||||
FetchDiscoverPage,
|
||||
FetchDetailSecondary,
|
||||
FetchDetailStreams,
|
||||
FetchIntroSegments,
|
||||
|
|
@ -63,6 +64,7 @@ impl EffectKind {
|
|||
EffectKind::FetchAddonManifest => "fetchAddonManifest",
|
||||
EffectKind::FetchAddonResource => "fetchAddonResource",
|
||||
EffectKind::FetchCatalogPage => "fetchCatalogPage",
|
||||
EffectKind::FetchDiscoverPage => "fetchDiscoverPage",
|
||||
EffectKind::FetchDetailSecondary => "fetchDetailSecondary",
|
||||
EffectKind::FetchDetailStreams => "fetchDetailStreams",
|
||||
EffectKind::FetchIntroSegments => "fetchIntroSegments",
|
||||
|
|
@ -112,6 +114,7 @@ impl EffectKind {
|
|||
"fetchAddonManifest" => EffectKind::FetchAddonManifest,
|
||||
"fetchAddonResource" => EffectKind::FetchAddonResource,
|
||||
"fetchCatalogPage" => EffectKind::FetchCatalogPage,
|
||||
"fetchDiscoverPage" => EffectKind::FetchDiscoverPage,
|
||||
"fetchDetailSecondary" => EffectKind::FetchDetailSecondary,
|
||||
"fetchDetailStreams" => EffectKind::FetchDetailStreams,
|
||||
"fetchIntroSegments" => EffectKind::FetchIntroSegments,
|
||||
|
|
@ -212,6 +215,7 @@ mod tests {
|
|||
EffectKind::FetchAddonManifest,
|
||||
EffectKind::FetchAddonResource,
|
||||
EffectKind::FetchCatalogPage,
|
||||
EffectKind::FetchDiscoverPage,
|
||||
EffectKind::FetchDetailSecondary,
|
||||
EffectKind::FetchDetailStreams,
|
||||
EffectKind::FetchIntroSegments,
|
||||
|
|
|
|||
Loading…
Reference in a new issue