From c6aca56f2729151ba0f4d8b405d0d350d77fd5ad Mon Sep 17 00:00:00 2001 From: oiupoyt Date: Thu, 27 Aug 2026 19:22:48 +0530 Subject: [PATCH] fix(auth): fix onboarding offline account creation and enable continue button --- .../src/view/onboarding/account.rs | 91 +++++++++++++------ packages/oneclient_auth/src/store.rs | 31 +++++-- 2 files changed, 88 insertions(+), 34 deletions(-) diff --git a/packages/oneclient_app/src/view/onboarding/account.rs b/packages/oneclient_app/src/view/onboarding/account.rs index 176fced8..8ee2e4e7 100644 --- a/packages/oneclient_app/src/view/onboarding/account.rs +++ b/packages/oneclient_app/src/view/onboarding/account.rs @@ -1,8 +1,12 @@ use freya::prelude::*; use oneclient_auth::MinecraftAccount; -use crate::components::{Avatar, Button, Icon, IconType, use_microsoft_login}; -use crate::hooks::{try_default_account, use_current_account}; +use crate::components::{ + Avatar, Button, Icon, IconType, TextInput, use_microsoft_login, +}; +use crate::hooks::{ + AddOfflineAccountKeys, try_default_account, use_add_offline_account, use_current_account, +}; use crate::routes::Route; use crate::theme::colors; use crate::view::onboarding::{ @@ -16,6 +20,9 @@ impl Component for OnboardingAccount { fn render(&self) -> impl IntoElement { let account_query = use_current_account(); let msa = use_microsoft_login(); + let add_offline = use_add_offline_account(); + + let offline_name = use_state(|| "Player".to_string()); let account = try_default_account(&account_query); let has_account = account.is_some(); @@ -26,40 +33,72 @@ impl Component for OnboardingAccount { .spacing(24.) .child(step_heading( "Account", - "Before you continue, we require you to own a copy of Minecraft: Java Edition.", + "Choose an offline username to play, or sign in with your Microsoft account.", )) .child(match &account { Some(account) => account_preview(account).into_element(), None => { let start = msa.clone(); + let add_offline_click = add_offline.clone(); + let name_val = offline_name.read().trim().to_string(); + let target_name = if name_val.is_empty() { + "Player".to_string() + } else { + name_val + }; + rect() .vertical() - .spacing(12.) + .spacing(16.) + .child( + rect() + .vertical() + .spacing(8.) + .child( + label() + .text("Play Offline:") + .font_size(14.) + .font_weight(FontWeight::SEMI_BOLD) + .color(colors::fg_primary()), + ) + .child( + rect() + .horizontal() + .spacing(8.) + .cross_align(Alignment::Center) + .child( + TextInput::new(offline_name.clone()) + .placeholder("Enter username") + .width(Size::px(220.)), + ) + .child( + Button::new() + .primary() + .large() + .on_press(move |_| { + add_offline_click.mutate(AddOfflineAccountKeys { + username: target_name.clone(), + }); + }) + .text("Play Offline"), + ), + ), + ) + .child( + rect() + .horizontal() + .cross_align(Alignment::Center) + .spacing(8.) + .child( + label() + .text("— or sign in with Microsoft —") + .font_size(12.) + .color(colors::fg_secondary()), + ), + ) .child(sign_in_card(msa.pending, msa.error.clone(), move |_| { start.start() })) - .child( - Button::new() - .secondary() - .large() - .on_press(move |_| { - spawn(async move { - if let Ok(state) = crate::launcher::state() { - if let Ok(acc) = state - .auth - .add_offline_account("Player".to_string()) - .await - { - let _ = state - .auth - .set_default_account(Some(acc.id)) - .await; - } - } - }); - }) - .text("Play Offline as Player"), - ) .into_element() } }) diff --git a/packages/oneclient_auth/src/store.rs b/packages/oneclient_auth/src/store.rs index 8e2e1738..4f03b338 100644 --- a/packages/oneclient_auth/src/store.rs +++ b/packages/oneclient_auth/src/store.rs @@ -23,8 +23,13 @@ impl CredentialsStore { return Ok(Self::default()); } - match polyio::read_json(&path).await { - Ok(store) => Ok(store), + match polyio::read_json::(&path).await { + Ok(mut store) => { + if store.default_user.is_none() && !store.users.is_empty() { + store.default_user = store.users.keys().copied().next(); + } + Ok(store) + } Err(err) => { tracing::warn!("failed to read auth file: {err}"); Ok(Self::default()) @@ -91,10 +96,6 @@ impl CredentialsStore { } fn insert_offline_account(&mut self, username: String) -> AuthResult { - if self.default_user.is_none() { - // will be set after inserting account - } - validate_offline_username(&username)?; if self @@ -102,11 +103,25 @@ impl CredentialsStore { .values() .any(|u| u.username.eq_ignore_ascii_case(&username)) { - return Err(AuthError::DuplicateUsername { username }); + if let Some(existing) = self + .users + .values() + .find(|u| u.username.eq_ignore_ascii_case(&username)) + .cloned() + { + if self.default_user.is_none() { + self.default_user = Some(existing.id); + } + return Ok(existing); + } } let account = offline_account(username); - self.users.insert(account.id, account.clone()); + let id = account.id; + self.users.insert(id, account.clone()); + if self.default_user.is_none() { + self.default_user = Some(id); + } Ok(account) }