* chore: deleted the download process from onboarding * fix: gate onboarding Finish on loaded bundles and correct failure copy * chore: drop unused install_cluster_bundles re-export from oneclient_core * chore: drop the unread predownload flag from the versions manifest --------- Co-authored-by: LynithDev <61880709+LynithDev@users.noreply.github.com>
191 lines
5.3 KiB
Rust
191 lines
5.3 KiB
Rust
use std::collections::{HashMap, HashSet};
|
|
|
|
use freya::prelude::*;
|
|
use oneclient_content::packages::ProviderId;
|
|
use oneclient_content::packages::types::SearchSort;
|
|
use oneclient_db::models::ClusterId;
|
|
|
|
#[derive(Clone)]
|
|
pub struct ActiveClusterState(pub State<Option<ClusterId>>);
|
|
|
|
pub fn use_provide_active_cluster(active: ActiveClusterState) {
|
|
use_hook(move || provide_root_context(active));
|
|
}
|
|
|
|
pub fn use_active_cluster_id() -> State<Option<ClusterId>> {
|
|
consume_root_context::<ActiveClusterState>().0
|
|
}
|
|
|
|
/// Startup curtain stays up past the Startup route until home content settles
|
|
/// so the app never reveals a half-populated home
|
|
#[derive(Clone, Copy)]
|
|
pub struct SplashState {
|
|
pub active: State<bool>,
|
|
pub home_ready: State<bool>,
|
|
}
|
|
|
|
pub fn use_provide_splash(state: SplashState) {
|
|
use_provide_root_context(move || state);
|
|
}
|
|
|
|
pub fn use_splash() -> SplashState {
|
|
consume_root_context::<SplashState>()
|
|
}
|
|
|
|
/// The settings value the window was built from, carried in from startup because
|
|
/// the settings channel is still on its defaults during the first frames
|
|
#[derive(Clone, Copy)]
|
|
pub struct StartMaximizedState(pub bool);
|
|
|
|
pub fn use_provide_start_maximized(state: StartMaximizedState) {
|
|
use_provide_root_context(move || state);
|
|
}
|
|
|
|
pub fn use_start_maximized() -> bool {
|
|
consume_root_context::<StartMaximizedState>().0
|
|
}
|
|
|
|
pub const BROWSER_COMPAT_DEFAULT: bool = true;
|
|
|
|
#[derive(Clone)]
|
|
pub struct BrowserCompatState(pub State<bool>);
|
|
|
|
pub fn use_provide_browser_compat(state: BrowserCompatState) {
|
|
use_hook(move || provide_root_context(state));
|
|
}
|
|
|
|
pub fn use_browser_compat() -> State<bool> {
|
|
consume_root_context::<BrowserCompatState>().0
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct BrowserTypeState(pub State<String>);
|
|
|
|
pub fn use_provide_browser_type(state: BrowserTypeState) {
|
|
use_hook(move || provide_root_context(state));
|
|
}
|
|
|
|
pub fn use_browser_type() -> State<String> {
|
|
consume_root_context::<BrowserTypeState>().0
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct LinkConfirmState(pub State<Option<String>>);
|
|
|
|
pub fn use_provide_link_confirm(state: LinkConfirmState) {
|
|
use_provide_root_context(move || state.clone());
|
|
}
|
|
|
|
pub fn use_link_confirm() -> State<Option<String>> {
|
|
consume_root_context::<LinkConfirmState>().0
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct BrowserUiState {
|
|
pub query: String,
|
|
pub provider: ProviderId,
|
|
pub categories: Vec<String>,
|
|
pub sort: SearchSort,
|
|
pub page: usize,
|
|
}
|
|
|
|
impl Default for BrowserUiState {
|
|
fn default() -> Self {
|
|
Self {
|
|
query: String::new(),
|
|
provider: ProviderId::Modrinth,
|
|
categories: Vec::new(),
|
|
sort: SearchSort::Relevance,
|
|
page: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct BrowserStateStore(pub State<HashMap<String, BrowserUiState>>);
|
|
|
|
pub fn use_provide_browser_state(store: BrowserStateStore) {
|
|
use_hook(move || provide_root_context(store));
|
|
}
|
|
|
|
pub fn use_browser_state_store() -> State<HashMap<String, BrowserUiState>> {
|
|
consume_root_context::<BrowserStateStore>().0
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct OnboardingSelectionState {
|
|
pub selected: State<HashSet<String>>,
|
|
/// Until set the shell keeps re-deriving `selected` from the catalog so a
|
|
/// late-settling bundle list still gets the right defaults
|
|
pub user_touched: State<bool>,
|
|
/// `None` means "no migration decision yet"
|
|
pub migrated_categories: State<Option<Vec<String>>>,
|
|
pub language: State<String>,
|
|
pub reduce_motion: State<bool>,
|
|
/// `None` = don't import
|
|
pub import_folder: State<Option<String>>,
|
|
pub import_dedicated: State<bool>,
|
|
pub picks_location: State<bool>,
|
|
}
|
|
|
|
pub fn use_provide_onboarding_selection(state: OnboardingSelectionState) {
|
|
use_hook(move || provide_root_context(state));
|
|
}
|
|
|
|
pub fn use_onboarding_selection() -> OnboardingSelectionState {
|
|
consume_root_context::<OnboardingSelectionState>()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use freya_testing::TestingRunner;
|
|
|
|
use super::*;
|
|
|
|
/// Stands in for a route layout: it owns the state and publishes it as a root
|
|
/// context, so unmounting it drops the value the context still points at
|
|
#[derive(PartialEq)]
|
|
struct Shell;
|
|
|
|
impl Component for Shell {
|
|
fn render(&self) -> impl IntoElement {
|
|
let active = use_state(|| None::<ClusterId>);
|
|
use_provide_active_cluster(ActiveClusterState(active));
|
|
rect().child(Reader)
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq)]
|
|
struct Reader;
|
|
|
|
impl Component for Reader {
|
|
fn render(&self) -> impl IntoElement {
|
|
let active = *use_active_cluster_id().read();
|
|
label().text(format!("{active:?}"))
|
|
}
|
|
}
|
|
|
|
fn app() -> impl IntoElement {
|
|
let mounted = use_consume::<State<bool>>();
|
|
rect().maybe_child(mounted().then(|| Shell.into_element()))
|
|
}
|
|
|
|
#[test]
|
|
fn a_remounted_shell_replaces_the_dropped_root_state() {
|
|
let (mut test, mut mounted) = TestingRunner::new(
|
|
app,
|
|
Size2D::new(300., 300.),
|
|
|runner| runner.provide_root_context(|| State::create(true)),
|
|
1.,
|
|
);
|
|
test.sync_and_update();
|
|
|
|
// Leaving the shell drops the state the root context holds
|
|
test.run_in(|| mounted.set(false));
|
|
test.sync_and_update();
|
|
|
|
// Coming back must not hand the reader that dropped state
|
|
test.run_in(|| mounted.set(true));
|
|
test.sync_and_update();
|
|
}
|
|
}
|