OneLauncher-Cracked/packages/oneclient_app/src/view/startup.rs
Julian Chang 29d1f1c9d2
Bugs
Fixed #492
Fixed #510
Fixed #506
Fixed #568
Fixed #582
Fixed #578
Fixed #567
Fixed #588
Fixed #585
Fixed #571
Fixed #587
Fixed #584
2026-07-15 13:41:43 -04:00

160 lines
5.2 KiB
Rust

use freya::animation::{AnimNum, Ease, Function, OnCreation, OnFinish, use_animation};
use freya::{prelude::*, router::*};
use crate::AppAssets;
use crate::Route;
use crate::hooks::{
terms_document, terms_is_loading, use_launcher, use_notifications_snapshot,
use_settings_snapshot, use_terms,
};
use crate::theme::colors;
#[derive(PartialEq)]
pub struct Startup;
impl Component for Startup {
fn render(&self) -> impl IntoElement {
let launcher = use_launcher();
let settings = use_settings_snapshot();
let notifications = use_notifications_snapshot();
let terms = use_terms();
let intro = use_animation(|conf| {
conf.on_creation(OnCreation::Run);
AnimNum::new(0., 1.)
.time(620)
.ease(Ease::Out)
.function(Function::Cubic)
});
let pulse = use_animation(|conf| {
conf.on_creation(OnCreation::Run);
conf.on_finish(OnFinish::reverse());
AnimNum::new(0.82, 1.0)
.time(1600)
.ease(Ease::InOut)
.function(Function::Sine)
});
let logo = use_memo(|| AppAssets::get_bytes("logo.svg").unwrap_or_default());
if launcher.ready && !launcher.fetching && !terms_is_loading(&terms) {
let document = terms_document(&terms);
let required_terms = document.as_ref().map(|doc| doc.version).unwrap_or(1);
let required_privacy = document
.as_ref()
.map(|doc| doc.privacy_version())
.unwrap_or(1);
let stale = settings.settings.accepted_tos_version < required_terms
|| settings.settings.accepted_privacy_version < required_privacy;
let destination = if !settings.settings.seen_onboarding {
Route::OnboardingWelcome {}
} else if stale {
Route::OnboardingTerms {}
} else {
Route::Home {}
};
let _ = RouterContext::get().replace(destination);
return rect().into_element();
}
let active = notifications.inbox.iter().find(|entry| entry.is_loading);
let (message, detail): (String, Option<String>) =
if let Some(err) = launcher.error.as_deref() {
(
"Couldn't start OneClient".to_string(),
Some(err.to_string()),
)
} else if let Some(entry) = active {
let detail = entry
.tasks
.iter()
.find(|t| t.total == 0 || t.current < t.total)
.map(|t| t.label.clone())
.or_else(|| entry.progress.map(|(c, t)| format!("{c} / {t}")));
(entry.title.clone(), detail)
} else if launcher.ready {
("Fetching versions and bundles...".to_string(), None)
} else {
("Starting OneClient...".to_string(), None)
};
let is_error = launcher.error.is_some();
let appear = intro.get().value();
let rise = (1.0 - appear) * 16.;
let breath = pulse.read().value();
let dot_color = if is_error {
colors::danger()
} else {
colors::brand()
};
let loading_row = rect()
.horizontal()
.cross_align(Alignment::Center)
.spacing(9.)
.child(
rect()
.width(Size::px(8.))
.height(Size::px(8.))
.corner_radius(CornerRadius::new_all(4.))
.background(dot_color),
)
.child(
label()
.text(message)
.font_size(14.)
.color(colors::fg_primary().with_a(180)),
);
let mut content = rect()
.center()
.vertical()
.spacing(14.)
.child(
svg(logo.read().cloned())
.width(Size::px(288.))
.height(Size::px(60.))
.color(colors::fg_primary()),
)
.child(
label()
.text("The only Minecraft launcher you'll need.")
.font_size(15.)
.color(colors::fg_primary().with_a(140)),
)
.child(rect().height(Size::px(14.)))
.child(loading_row);
if let Some(detail) = detail {
content = content.child(
label()
.text(detail)
.font_size(12.)
.max_lines(1)
.color(colors::fg_secondary().with_a(180)),
);
}
let content = content
.position(Position::new_absolute())
.width(Size::fill())
.height(Size::fill())
.center()
.opacity(appear * breath)
.margin(Gaps::new(rise, 0., 0., 0.));
rect()
.width(Size::fill())
.height(Size::fill())
.background(colors::page())
.window_drag()
.child(content)
.into_element()
}
}