dash-frontend: tab titles, home screen username
This commit is contained in:
@@ -27,7 +27,13 @@
|
||||
<!-- left/right separator (menu and rest) -->
|
||||
<div flex_direction="row" gap="8" width="100%" height="100%">
|
||||
<!-- LEFT MENU -->
|
||||
<div id="menu" width="~size_size" min_width="~side_size" max_width="~side_size" height="100%" align_items="center" justify_content="center">
|
||||
<div id="menu"
|
||||
width="~size_size"
|
||||
min_width="~side_size"
|
||||
max_width="~side_size"
|
||||
height="100%"
|
||||
align_items="center"
|
||||
justify_content="center">
|
||||
<rectangle
|
||||
width="100%"
|
||||
round="100%"
|
||||
@@ -48,21 +54,34 @@
|
||||
</div>
|
||||
<!-- REST -->
|
||||
<!-- content/bottom panel separator -->
|
||||
<div flex_direction="column" gap="8" flex_grow="1">
|
||||
<div
|
||||
flex_direction="column"
|
||||
gap="8"
|
||||
width="100%"
|
||||
height="100%"
|
||||
overflow_x="scroll">
|
||||
<!-- CONTENT -->
|
||||
<rectangle
|
||||
color2="#0d131acc" color="#244179aa" gradient="vertical" round="8" overflow_y="hidden"
|
||||
justify_content="center"
|
||||
color2="#0d131acc"
|
||||
color="#244179aa"
|
||||
gradient="vertical"
|
||||
round="8"
|
||||
flex_grow="1"
|
||||
width="100%"
|
||||
overflow_y="scroll"
|
||||
>
|
||||
<div
|
||||
id="content"
|
||||
overflow_x="scroll"
|
||||
overflow_y="scroll"
|
||||
align_items="center"
|
||||
justify_content="center"
|
||||
flex_direction="column"
|
||||
gap="24"
|
||||
padding_top="8"
|
||||
padding_bottom="8"
|
||||
padding_left="16"
|
||||
padding_right="16"
|
||||
gap="8"
|
||||
width="100%"
|
||||
min_height="100%"
|
||||
>
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
justify_content="center"
|
||||
flex_direction="column">
|
||||
<sprite src="${icon}" width="32" height="32" />
|
||||
<label weight="bold" size="18" text="${text}" />
|
||||
<label weight="bold" size="18" text="${text}" translation="${translation}" />
|
||||
</div>
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
|
||||
<elements>
|
||||
<label text="Apps" size="64" weight="bold" />
|
||||
<label text="bottom text" size="16" weight="bold" color="#FFFFFF88" />
|
||||
<TabTitle translation="APPLICATIONS" icon="dashboard/apps.svg" />
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -1,5 +1,7 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
|
||||
<elements>
|
||||
<label text="Games" size="32" weight="bold" />
|
||||
<TabTitle translation="GAMES" icon="dashboard/games.svg" />
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -2,17 +2,23 @@
|
||||
<include src="../t_menu_button.xml" />
|
||||
|
||||
<elements>
|
||||
<sprite src="dashboard/wayvr_dashboard.svg" min_width="96" min_height="96" />
|
||||
<label text="Hello, user!" size="32" weight="bold" />
|
||||
<label text="Connected to wlx-overlay-s" size="16" weight="bold" color="#bbffbb" />
|
||||
<div
|
||||
flex_direction="column"
|
||||
justify_content="center"
|
||||
align_items="center"
|
||||
flex_grow="1"
|
||||
gap="24">
|
||||
<sprite src="dashboard/wayvr_dashboard.svg" width="96" height="96" />
|
||||
<label id="label_hello" size="32" weight="bold" />
|
||||
|
||||
<!-- main button list -->
|
||||
<div flex_direction="row" gap="8" margin_top="32">
|
||||
<MenuButton id="btn_apps" icon="dashboard/apps.svg" text="Apps" />
|
||||
<MenuButton id="btn_games" icon="dashboard/games.svg" text="Games" />
|
||||
<MenuButton id="btn_monado" icon="dashboard/monado.svg" text="Monado" />
|
||||
<MenuButton id="btn_processes" icon="dashboard/window.svg" text="Processes" />
|
||||
<MenuButton id="btn_settings" icon="dashboard/settings.svg" text="Settings" />
|
||||
<!-- main button list -->
|
||||
<div flex_direction="row" gap="8">
|
||||
<MenuButton id="btn_apps" icon="dashboard/apps.svg" translation="APPLICATIONS" />
|
||||
<MenuButton id="btn_games" icon="dashboard/games.svg" translation="GAMES" />
|
||||
<MenuButton id="btn_monado" icon="dashboard/monado.svg" text="Monado" />
|
||||
<MenuButton id="btn_processes" icon="dashboard/window.svg" translation="PROCESSES" />
|
||||
<MenuButton id="btn_settings" icon="dashboard/settings.svg" translation="SETTINGS" />
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -1,5 +1,7 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
|
||||
<elements>
|
||||
<label text="Monado" size="32" weight="bold" />
|
||||
<TabTitle translation="MONADO_RUNTIME" icon="dashboard/monado.svg" />
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -1,5 +1,7 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
|
||||
<elements>
|
||||
<label text="Processes" size="32" weight="bold" />
|
||||
<TabTitle translation="PROCESSES" icon="dashboard/window.svg" />
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -1,5 +1,7 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
|
||||
<elements>
|
||||
<label text="Settings" size="32" weight="bold" />
|
||||
<TabTitle translation="SETTINGS" icon="dashboard/settings.svg" />
|
||||
</elements>
|
||||
</layout>
|
||||
9
dash-frontend/assets/gui/tab/t_tab_title.xml
Normal file
9
dash-frontend/assets/gui/tab/t_tab_title.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<layout>
|
||||
<!-- translation, icon -->
|
||||
<template name="TabTitle">
|
||||
<div gap="8" align_items="center">
|
||||
<sprite src="${icon}" width="24" height="24" />
|
||||
<label translation="${translation}" size="18" weight="bold" />
|
||||
</div>
|
||||
</template>
|
||||
</layout>
|
||||
9
dash-frontend/assets/lang/de.json
Normal file
9
dash-frontend/assets/lang/de.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"HOME_SCREEN": "Startbildschirm",
|
||||
"MONADO_RUNTIME": "„Monado”-Laufzeitumgebung",
|
||||
"APPLICATIONS": "Anwendungen",
|
||||
"GAMES": "Spiele",
|
||||
"SETTINGS": "Einstellungen",
|
||||
"PROCESSES": "Prozesse",
|
||||
"HELLO_USER": "Hallo, {USER}!"
|
||||
}
|
||||
@@ -1 +1,9 @@
|
||||
{}
|
||||
{
|
||||
"HOME_SCREEN": "Home",
|
||||
"MONADO_RUNTIME": "„Monado” runtime",
|
||||
"APPLICATIONS": "Applications",
|
||||
"GAMES": "Games",
|
||||
"SETTINGS": "Settings",
|
||||
"PROCESSES": "Processes",
|
||||
"HELLO_USER": "Hello, {USER}!"
|
||||
}
|
||||
|
||||
9
dash-frontend/assets/lang/es.json
Normal file
9
dash-frontend/assets/lang/es.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"HOME_SCREEN": "Inicio",
|
||||
"MONADO_RUNTIME": "„Monado” tiempo de ejecución",
|
||||
"APPLICATIONS": "Aplicaciones",
|
||||
"GAMES": "Juegos",
|
||||
"SETTINGS": "Ajustes",
|
||||
"PROCESSES": "Procesos",
|
||||
"HELLO_USER": "¡Hola, {USER}!"
|
||||
}
|
||||
9
dash-frontend/assets/lang/ja.json
Normal file
9
dash-frontend/assets/lang/ja.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"HOME_SCREEN": "ホーム",
|
||||
"MONADO_RUNTIME": "「Monado」ランタイム",
|
||||
"APPLICATIONS": "アプリケーション",
|
||||
"GAMES": "ゲーム",
|
||||
"SETTINGS": "設定",
|
||||
"PROCESSES": "プロセス",
|
||||
"HELLO_USER": "こんにちは、{USER}!"
|
||||
}
|
||||
9
dash-frontend/assets/lang/pl.json
Normal file
9
dash-frontend/assets/lang/pl.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"HOME_SCREEN": "Ekran główny",
|
||||
"MONADO_RUNTIME": "„Monado” środowisko uruchomieniowe",
|
||||
"APPLICATIONS": "Aplikacje",
|
||||
"GAMES": "Gry",
|
||||
"SETTINGS": "Ustawienia",
|
||||
"PROCESSES": "Procesy",
|
||||
"HELLO_USER": "Witaj, {USER}!"
|
||||
}
|
||||
@@ -20,6 +20,7 @@ use crate::tab::{
|
||||
|
||||
mod assets;
|
||||
mod tab;
|
||||
mod various;
|
||||
|
||||
pub struct Frontend {
|
||||
pub layout: RcLayout,
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
use wgui::{
|
||||
components::button::ComponentButton,
|
||||
i18n::Translation,
|
||||
parser::{ParseDocumentParams, ParserState},
|
||||
widget::label::WidgetLabel,
|
||||
};
|
||||
|
||||
use crate::tab::{Tab, TabParams, TabType};
|
||||
use crate::{
|
||||
tab::{Tab, TabParams, TabType},
|
||||
various,
|
||||
};
|
||||
|
||||
pub struct TabHome {
|
||||
#[allow(dead_code)]
|
||||
@@ -16,6 +21,18 @@ impl Tab for TabHome {
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_label_hello(label_hello: &mut WidgetLabel, i18n: &mut wgui::i18n::I18n) {
|
||||
let mut username = various::get_username();
|
||||
// first character as uppercase
|
||||
if let Some(first) = username.chars().next() {
|
||||
let first = first.to_uppercase().to_string();
|
||||
username.replace_range(0..1, &first);
|
||||
}
|
||||
|
||||
let translated = i18n.translate_and_replace("HELLO_USER", ("{USER}", &username));
|
||||
label_hello.set_text_simple(i18n, Translation::from_raw_text(&translated));
|
||||
}
|
||||
|
||||
impl TabHome {
|
||||
pub fn new(params: TabParams) -> anyhow::Result<Self> {
|
||||
let state = wgui::parser::parse_from_assets(
|
||||
@@ -29,6 +46,9 @@ impl TabHome {
|
||||
params.parent_id,
|
||||
)?;
|
||||
|
||||
let mut label_hello = state.fetch_widget_as::<WidgetLabel>(¶ms.layout.state, "label_hello")?;
|
||||
configure_label_hello(&mut label_hello, &mut params.globals.i18n());
|
||||
|
||||
let btn_apps = state.fetch_component_as::<ComponentButton>("btn_apps")?;
|
||||
let btn_games = state.fetch_component_as::<ComponentButton>("btn_games")?;
|
||||
let btn_monado = state.fetch_component_as::<ComponentButton>("btn_monado")?;
|
||||
|
||||
6
dash-frontend/src/various.rs
Normal file
6
dash-frontend/src/various.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
pub fn get_username() -> String {
|
||||
match std::env::var("USER") {
|
||||
Ok(user) => user,
|
||||
Err(_) => String::from("anonymous"),
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ if (template_name === undefined) {
|
||||
}
|
||||
|
||||
if (lang_path === undefined) {
|
||||
console.log("LANG_PATH not set. Try \"LANG_PATH=../../uidev/assets/lang/ ./run.sh\"");
|
||||
console.log("LANG_PATH is not set. Try one of these:\n\nLANG_PATH=../../uidev/assets/lang/ ./run.sh\nLANG_PATH=../../dash-frontend/assets/lang/ ./run.sh\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,10 +77,7 @@ impl I18n {
|
||||
match lang.as_str() {
|
||||
"en" | "pl" | "it" | "ja" | "es" => {}
|
||||
_ => {
|
||||
log::warn!(
|
||||
"Unsupported language \"{}\", defaulting to \"en\".",
|
||||
lang.as_str()
|
||||
);
|
||||
log::warn!("Unsupported language \"{}\", defaulting to \"en\".", lang.as_str());
|
||||
|
||||
lang = String::from("en");
|
||||
}
|
||||
@@ -111,4 +108,9 @@ impl I18n {
|
||||
log::error!("missing translation for key \"{translation_key}\"");
|
||||
Rc::from(translation_key) // show translation key as a fallback
|
||||
}
|
||||
|
||||
pub fn translate_and_replace(&mut self, translation_key: &str, to_replace: (&str, &str)) -> String {
|
||||
let translated = self.translate(translation_key);
|
||||
translated.replace(to_replace.0, to_replace.1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,11 +68,11 @@ pub struct ParserState {
|
||||
impl ParserState {
|
||||
pub fn fetch_component_by_id(&self, id: &str) -> anyhow::Result<Component> {
|
||||
let Some(weak) = self.components_by_id.get(id) else {
|
||||
anyhow::bail!("Component by ID \"{}\" doesn't exist", id);
|
||||
anyhow::bail!("Component by ID \"{id}\" doesn't exist");
|
||||
};
|
||||
|
||||
let Some(component) = weak.upgrade() else {
|
||||
anyhow::bail!("Component by ID \"{}\" doesn't exist", id);
|
||||
anyhow::bail!("Component by ID \"{id}\" doesn't exist");
|
||||
};
|
||||
|
||||
Ok(Component(component))
|
||||
@@ -80,11 +80,11 @@ impl ParserState {
|
||||
|
||||
pub fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result<Component> {
|
||||
let Some(weak) = self.components_by_widget_id.get(&widget_id) else {
|
||||
anyhow::bail!("Component by widget ID \"{:?}\" doesn't exist", widget_id);
|
||||
anyhow::bail!("Component by widget ID \"{widget_id:?}\" doesn't exist");
|
||||
};
|
||||
|
||||
let Some(component) = weak.upgrade() else {
|
||||
anyhow::bail!("Component by widget ID \"{:?}\" doesn't exist", widget_id);
|
||||
anyhow::bail!("Component by widget ID \"{widget_id:?}\" doesn't exist");
|
||||
};
|
||||
|
||||
Ok(Component(component))
|
||||
@@ -94,7 +94,7 @@ impl ParserState {
|
||||
let component = self.fetch_component_by_id(id)?;
|
||||
|
||||
if !(*component.0).as_any().is::<T>() {
|
||||
anyhow::bail!("fetch_component_as({}): type not matching", id);
|
||||
anyhow::bail!("fetch_component_as({id}): type not matching");
|
||||
}
|
||||
|
||||
// safety: we already checked it above, should be safe to directly cast it
|
||||
@@ -105,7 +105,7 @@ impl ParserState {
|
||||
let component = self.fetch_component_by_widget_id(widget_id)?;
|
||||
|
||||
if !(*component.0).as_any().is::<T>() {
|
||||
anyhow::bail!("fetch_component_by_widget_id({:?}): type not matching", widget_id);
|
||||
anyhow::bail!("fetch_component_by_widget_id({widget_id:?}): type not matching");
|
||||
}
|
||||
|
||||
// safety: we already checked it above, should be safe to directly cast it
|
||||
@@ -115,22 +115,37 @@ impl ParserState {
|
||||
pub fn get_widget_id(&self, id: &str) -> anyhow::Result<WidgetID> {
|
||||
match self.ids.get(id) {
|
||||
Some(id) => Ok(*id),
|
||||
None => anyhow::bail!("Widget by ID \"{}\" doesn't exist", id),
|
||||
None => anyhow::bail!("Widget by ID \"{id}\" doesn't exist"),
|
||||
}
|
||||
}
|
||||
|
||||
// returns widget and its id at once
|
||||
pub fn fetch_widget(&self, state: &LayoutState, id: &str) -> anyhow::Result<WidgetPair> {
|
||||
let widget_id = self.get_widget_id(id)?;
|
||||
let widget = state
|
||||
.widgets
|
||||
.get(widget_id)
|
||||
.ok_or_else(|| anyhow::anyhow!("fetch_widget({}): widget not found", id))?;
|
||||
.ok_or_else(|| anyhow::anyhow!("fetch_widget({id}): widget not found"))?;
|
||||
Ok(WidgetPair {
|
||||
id: widget_id,
|
||||
widget: widget.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fetch_widget_as<'a, T: 'static>(&self, state: &'a LayoutState, id: &str) -> anyhow::Result<RefMut<'a, T>> {
|
||||
let widget_id = self.get_widget_id(id)?;
|
||||
let widget = state
|
||||
.widgets
|
||||
.get(widget_id)
|
||||
.ok_or_else(|| anyhow::anyhow!("fetch_widget_as({id}): widget not found"))?;
|
||||
|
||||
let casted = widget
|
||||
.get_as_mut::<T>()
|
||||
.ok_or_else(|| anyhow::anyhow!("fetch_widget_as({id}): failed to cast"))?;
|
||||
|
||||
Ok(casted)
|
||||
}
|
||||
|
||||
pub fn process_template<U1, U2>(
|
||||
&mut self,
|
||||
doc_params: &ParseDocumentParams,
|
||||
@@ -141,7 +156,7 @@ impl ParserState {
|
||||
template_parameters: HashMap<Rc<str>, Rc<str>>,
|
||||
) -> anyhow::Result<()> {
|
||||
let Some(template) = self.templates.get(template_name) else {
|
||||
anyhow::bail!("no template named \"{}\" found", template_name);
|
||||
anyhow::bail!("no template named \"{template_name}\" found");
|
||||
};
|
||||
|
||||
let mut ctx = ParserContext {
|
||||
@@ -231,7 +246,7 @@ fn get_tag_by_name<'a>(node: &roxmltree::Node<'a, 'a>, name: &str) -> Option<rox
|
||||
}
|
||||
|
||||
fn require_tag_by_name<'a>(node: &roxmltree::Node<'a, 'a>, name: &str) -> anyhow::Result<roxmltree::Node<'a, 'a>> {
|
||||
get_tag_by_name(node, name).ok_or_else(|| anyhow::anyhow!("Tag \"{}\" not found", name))
|
||||
get_tag_by_name(node, name).ok_or_else(|| anyhow::anyhow!("Tag \"{name}\" not found"))
|
||||
}
|
||||
|
||||
fn print_invalid_attrib(key: &str, value: &str) {
|
||||
|
||||
@@ -23,9 +23,15 @@ pub fn parse_widget_label<'a, U1, U2>(
|
||||
for (key, value) in attribs {
|
||||
match &*key {
|
||||
"text" => {
|
||||
params.content = Translation::from_raw_text(&value);
|
||||
if !value.is_empty() {
|
||||
params.content = Translation::from_raw_text(&value);
|
||||
}
|
||||
}
|
||||
"translation" => {
|
||||
if !value.is_empty() {
|
||||
params.content = Translation::from_translation_key(&value);
|
||||
}
|
||||
}
|
||||
"translation" => params.content = Translation::from_translation_key(&value),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<template name="Set">
|
||||
<Button macro="button_style" _press="::OverlayToggle ${handle}">
|
||||
<sprite width="40" height="40" color="~set_color" src="watch/set2.svg" />
|
||||
<div position="absolute" margin_top="11" >
|
||||
<div position="absolute" margin_top="11">
|
||||
<label text="${display}" size="24" color="#000000" weight="bold" />
|
||||
</div>
|
||||
</Button>
|
||||
@@ -74,4 +74,4 @@
|
||||
</rectangle>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
</layout>
|
||||
Reference in New Issue
Block a user