Welcome screen basics

This commit is contained in:
Aleksander 2026-05-13 16:36:13 +02:00
parent 1591466a8d
commit 1cc537807d
14 changed files with 226 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Design Icons by Pictogrammers - https://github.com/Templarian/MaterialDesign/blob/master/LICENSE --><path fill="currentColor" d="M1.5 4v1.5c0 4.15 2.21 7.78 5.5 9.8V20h15v-2c0-2.66-5.33-4-8-4h-.25C9 14 5 10 5 5.5V4m9 0a4 4 0 0 0-4 4a4 4 0 0 0 4 4a4 4 0 0 0 4-4a4 4 0 0 0-4-4"/></svg>

After

Width:  |  Height:  |  Size: 391 B

View File

@ -0,0 +1,22 @@
<layout>
<template name="Pip">
<rectangle id="pip" width="8" height="8" round="100%" color="${COLOR}"/>
</template>
<elements>
<div flex_direction="column" flex_grow="1" gap="16" align_items="center" overflow_y="hidden">
<!-- Content -->
<div id="content" flex_direction="column" flex_grow="1" align_items="center" justify_content="center" gap="16" overflow_y="scroll">
<!-- filled-in at runtime -->
</div>
<!-- Page buttons -->
<div flex_direction="row" gap="8" align_items="center">
<Button id="btn_prev" width="32" height="32" round="100%" sprite_src_builtin="dashboard/arrow_left.svg" />
<div id="pips" gap="4" align_items="center">
<!-- filled-in at runtime -->
</div>
<Button id="btn_next" width="32" height="32" round="100%" sprite_src_builtin="dashboard/arrow_right.svg" />
</div>
</div>
</elements>
</layout>

View File

@ -0,0 +1,13 @@
<layout>
<elements>
<image src_builtin="dashboard/splash.png" min_width="431" min_height="128" />
<rectangle color="#FFFFFF11" width="100%" height="2"/>
<label weight="bold" size="32" text="Hi there!"/>
<label weight="bold" size="20" text="Thank you for installing WayVR ❤️"/>
<label size="20" margin_top="16" text="Let us guide you through your first steps."/>
<label size="20" text="Press &quot;Next&quot; button below to get started."/>
</elements>
</layout>

View File

@ -0,0 +1,5 @@
<layout>
<elements>
<label text="Page 1"/>
</elements>
</layout>

View File

@ -0,0 +1,5 @@
<layout>
<elements>
<label text="Page 2" weight="bold" size="20"/>
</elements>
</layout>

View File

@ -0,0 +1,5 @@
<layout>
<elements>
<label text="Page 3" weight="bold" size="50"/>
</elements>
</layout>

View File

@ -0,0 +1,7 @@
<layout>
<elements>
<label text="Page 4" shadow="#000000" shadow_x="10" shadow_y="10" color="#FF00FF" size="30"/>
<label text="Page 4" shadow="#000000" shadow_x="10" shadow_y="10" weight="bold" color="#FFFF00" size="30"/>
<label text="Page 4" shadow="#000000" shadow_x="10" shadow_y="10" color="#00FFFF" size="30"/>
</elements>
</layout>

View File

@ -101,6 +101,7 @@
"SCROLL_SPEED": "Scroll speed",
"SELECT_VARIANT": "Select variant",
"SETS_ON_WATCH": "Sets on watch",
"SHOW_WELCOME_SCREEN": "Show welcome screen",
"SKYBOX": "Skybox",
"SKYMAP_ALREADY_DOWNLOADED": "This skymap is already downloaded. Select desired action.",
"SPACE_DRAG_MULTIPLIER": "Space drag multiplier",
@ -154,6 +155,7 @@
},
"GAMES": "Games",
"GENERAL_SETTINGS": "General settings",
"GETTING_STARTED": "Getting started",
"HEIGHT": "Height",
"HELLO": "Hello!",
"HELLO_USER": "Hello, {USER}!",

View File

@ -26,7 +26,10 @@ use wlx_common::{
use crate::{
assets,
tab::{Tab, TabType, apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, settings::TabSettings},
tab::{
Tab, TabType, apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, settings::TabSettings,
welcome::TabWelcome,
},
util::{
popup_manager::{MountPopupOnceParams, PopupManager, PopupManagerParams},
toast_manager::ToastManager,
@ -390,6 +393,7 @@ impl<T: 'static> Frontend<T> {
self.layout.remove_children(widget_content.id);
let (tab_translation, icon_path) = match tab_type {
TabType::Welcome => ("GETTING_STARTED", "dashboard/welcome.svg"),
TabType::Home => ("HOME_SCREEN", "dashboard/home.svg"),
TabType::Apps => ("APPLICATIONS", "dashboard/apps.svg"),
TabType::Games => ("GAMES", "dashboard/games.svg"),
@ -400,6 +404,7 @@ impl<T: 'static> Frontend<T> {
self.set_tab_title(tab_translation, icon_path)?;
let tab: Box<dyn Tab<T>> = match tab_type {
TabType::Welcome => Box::new(TabWelcome::new(self, widget_content.id, data)?),
TabType::Home => Box::new(TabHome::new(self, widget_content.id, data)?),
TabType::Apps => Box::new(TabApps::new(self, widget_content.id, data)?),
TabType::Games => Box::new(TabGames::new(self, widget_content.id)?),

View File

@ -5,6 +5,7 @@ pub mod games;
pub mod home;
pub mod monado;
pub mod settings;
pub mod welcome;
#[derive(Clone, Copy, Debug)]
pub enum TabType {
@ -13,6 +14,7 @@ pub enum TabType {
Games,
Monado,
Settings,
Welcome,
}
pub trait Tab<T> {

View File

@ -81,6 +81,7 @@ enum Task {
RestartSoftware,
RemoveAutostartApp(Rc<str>),
SetTab(TabNameEnum),
ShowWelcomeScreen,
}
struct SettingsMountParams<'a> {
@ -136,6 +137,9 @@ impl<T> Tab<T> for TabSettings<T> {
Task::SetTab(tab) => {
self.set_tab(frontend, data, tab)?;
}
Task::ShowWelcomeScreen => {
self.frontend_tasks.push(FrontendTask::SetTab(TabType::Welcome));
}
Task::UpdateBool(setting, n) => {
self.tasks.push(Task::SettingUpdated(setting));
if let Some(task) = setting.get_frontend_task() {

View File

@ -50,6 +50,13 @@ impl State {
"dashboard/refresh.svg",
Task::RestartSoftware,
)?;
options_danger_button(
par.mp,
c,
"APP_SETTINGS.SHOW_WELCOME_SCREEN",
"dashboard/welcome.svg",
Task::ShowWelcomeScreen,
)?;
Ok(State {})
}
}

View File

@ -0,0 +1,147 @@
use std::{collections::HashMap, marker::PhantomData, rc::Rc};
use wgui::{
assets::AssetPath,
components::button::ComponentButton,
globals::WguiGlobals,
layout::{Layout, WidgetID},
parser::{Fetchable, ParseDocumentParams, ParserState},
task::Tasks,
};
use crate::{
frontend::Frontend,
tab::{Tab, TabType},
};
#[derive(Clone)]
#[allow(clippy::enum_variant_names)]
enum Task {
SetPage(u8),
SetPageNext,
SetPagePrev,
}
pub struct TabWelcome<T> {
#[allow(dead_code)]
pub state: ParserState,
marker: PhantomData<T>,
tasks: Tasks<Task>,
current_page: u8,
id_pips: WidgetID,
id_content: WidgetID,
}
const PAGE_COUNT: u8 = 5; // 0-4 inclusive
impl<T> Tab<T> for TabWelcome<T> {
fn get_type(&self) -> TabType {
TabType::Welcome
}
fn update(&mut self, frontend: &mut Frontend<T>, _time_ms: u32, _user_data: &mut T) -> anyhow::Result<()> {
for task in self.tasks.drain() {
match task {
Task::SetPage(page_num) => {
self.set_page(&mut frontend.layout, page_num)?;
}
Task::SetPageNext => {
if self.current_page < PAGE_COUNT - 1 {
self.tasks.push(Task::SetPage(self.current_page + 1));
}
}
Task::SetPagePrev => {
if self.current_page > 0 {
self.tasks.push(Task::SetPage(self.current_page - 1));
}
}
}
}
Ok(())
}
}
fn doc_params(globals: &WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/tab/welcome.xml"),
extra: Default::default(),
}
}
impl<T> TabWelcome<T> {
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID, _data: &mut T) -> anyhow::Result<Self> {
let state = wgui::parser::parse_from_assets(&doc_params(&frontend.globals), &mut frontend.layout, parent_id)?;
let tasks = Tasks::<Task>::new();
let btn_prev = state.fetch_component_as::<ComponentButton>("btn_prev")?;
let btn_next = state.fetch_component_as::<ComponentButton>("btn_next")?;
tasks.handle_button(&btn_prev, Task::SetPagePrev);
tasks.handle_button(&btn_next, Task::SetPageNext);
let id_pips = state.get_widget_id("pips")?;
let id_content = state.get_widget_id("content")?;
tasks.push(Task::SetPage(0));
Ok(Self {
state,
marker: PhantomData,
current_page: 0,
id_pips,
id_content,
tasks,
})
}
fn refresh_pips(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
layout.remove_children(self.id_pips);
let globals = layout.state.globals.clone();
for i in 0..PAGE_COUNT {
let mut vars = HashMap::<Rc<str>, Rc<str>>::new();
let is_selected = i == self.current_page;
vars.insert(
Rc::from("COLOR"),
Rc::from(if is_selected { "#FFFFFF" } else { "#FFFFFF11" }),
);
self
.state
.instantiate_template(&doc_params(&globals), "Pip", layout, self.id_pips, vars)?
}
Ok(())
}
fn fill_page(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
layout.remove_children(self.id_content);
let globals = layout.state.globals.clone();
let _ = wgui::parser::parse_from_assets(
&ParseDocumentParams {
globals,
path: AssetPath::BuiltIn(&format!("gui/tab/welcome_page_{}.xml", self.current_page)),
extra: Default::default(),
},
layout,
self.id_content,
)?;
Ok(())
}
fn set_page(&mut self, layout: &mut Layout, page_num: u8) -> anyhow::Result<()> {
self.current_page = page_num;
self.refresh_pips(layout)?;
self.fill_page(layout)?;
Ok(())
}
}