diff --git a/fonts/noto_light.ttf b/fonts/noto_light.ttf deleted file mode 100644 index 54f15df..0000000 Binary files a/fonts/noto_light.ttf and /dev/null differ diff --git a/fonts/noto_sc_reg.otf b/fonts/noto_sc_reg.otf new file mode 100644 index 0000000..25622c9 Binary files /dev/null and b/fonts/noto_sc_reg.otf differ diff --git a/src/gui/app.rs b/src/gui/app.rs index 04b453e..93ca7ce 100644 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -16,11 +16,9 @@ use std::cmp::min; use eframe::Frame; use egui::{Color32, Context, Stroke}; -use egui::epaint::Shadow; use egui::style::Margin; -use wgpu::Color; -use crate::gui::COLOR_YELLOW; +use crate::gui::{COLOR_LIGHT, COLOR_YELLOW}; use crate::gui::platform::PlatformCallbacks; use crate::gui::screens::{Root, Screen}; @@ -31,71 +29,30 @@ pub struct PlatformApp { pub struct App { root: Root, - network_panel_open: bool } impl Default for App { fn default() -> Self { Self { root: Root::default(), - network_panel_open: false } } } impl App { pub fn ui(&mut self, ctx: &Context, frame: &mut Frame, cb: &dyn PlatformCallbacks) { - let network_panel_open = self.network_panel_open || dual_panel_available(frame); - + let Self { root } = self; egui::CentralPanel::default() .frame(egui::Frame { inner_margin: Margin::same(0.0), outer_margin: Margin::same(0.0), - fill: COLOR_YELLOW, + stroke: Stroke::NONE, + fill: COLOR_LIGHT, .. Default::default() }) .show(ctx, |ui| { - - egui::SidePanel::left("network_panel") - .resizable(false) - .exact_width(if dual_panel_available(frame) { - min(frame.info().window_info.size.x as i64, 500) as f32 - } else { - frame.info().window_info.size.x - }) - .frame(egui::Frame { - inner_margin: Margin::same(0.0), - outer_margin: Margin::same(0.0), - rounding: Default::default(), - shadow: Shadow::NONE, - fill: COLOR_YELLOW, - stroke: Stroke::NONE, - }) - .show_animated_inside(ui, network_panel_open, |ui| { - //TODO: Network content - ui.vertical_centered(|ui| { - ui.heading("🖧 Node"); - }); - - ui.separator(); - }); - - egui::CentralPanel::default().frame(egui::containers::Frame { - inner_margin: Margin::same(3.0), - stroke: Stroke::new(1.0, Color32::from_gray(5)), - ..Default::default() - }).show_inside(ui, |ui| { - self.root.ui(ui, cb); - }); + root.ui(ui, frame, cb) }); } } -pub fn dual_panel_available(frame: &mut Frame) -> bool { - is_landscape(frame) && frame.info().window_info.size.x > 500.0 -} - -pub fn is_landscape(frame: &mut Frame) -> bool { - return frame.info().window_info.size.x > frame.info().window_info.size.y -} - diff --git a/src/gui/mod.rs b/src/gui/mod.rs index a7b9561..13f70ce 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -14,7 +14,6 @@ pub use app::App; -pub use app::is_landscape; pub use app::PlatformApp; pub mod platform; @@ -24,11 +23,13 @@ pub mod views; mod app; pub const COLOR_YELLOW: egui::Color32 = egui::Color32::from_rgb(254, 241, 2); +pub const COLOR_LIGHT: egui::Color32 = egui::Color32::from_gray(240); +pub const COLOR_DARK: egui::Color32 = egui::Color32::from_gray(60); -pub const SYM_ARROW_BACK: &str = "â‡Ķ"; -pub const SYM_ARROW_FORWARD: &str = "â‡Ļ"; +// Material icons chars +pub const SYM_ARROW_BACK: &str = "";//""; pub const SYM_ADD: &str = "ïž‹"; -pub const SYM_MENU: &str = "∷"; -pub const SYM_ACCOUNTS: &str = "🗄"; -pub const SYM_NETWORK: &str = "🖧"; +pub const SYM_ACCOUNTS: &str = ""; +pub const SYM_NETWORK: &str = "îĒ”"; +pub const SYM_SETTINGS: &str = "îĒļ";//""; diff --git a/src/gui/platform/android/mod.rs b/src/gui/platform/android/mod.rs index dc6bb1d..861cd26 100644 --- a/src/gui/platform/android/mod.rs +++ b/src/gui/platform/android/mod.rs @@ -94,35 +94,62 @@ impl PlatformApp { let mut fonts = egui::FontDefinitions::default(); // Tweak emoji icons to look nice against main font y-offset + // fonts.font_data.insert( + // "emoji-icon-font".to_owned(), + // egui::FontData { + // font: fonts.font_data.get("emoji-icon-font").unwrap().clone().font, + // index: 0, + // tweak: egui::FontTweak { + // scale: 0.88, + // y_offset_factor: 0.26, + // y_offset: 0.0, + // }, + // }); + + // fonts.font_data.insert( + // "material".to_owned(), + // egui::FontData::from_static(include_bytes!( + // "../../../../fonts/material-light.ttf" + // )).tweak(egui::FontTweak { + // scale: 1.0, + // y_offset_factor: 0.06, + // y_offset: 0.0 + // }), + // ); fonts.font_data.insert( - "emoji-icon-font".to_owned(), - egui::FontData { - font: fonts.font_data.get("emoji-icon-font").unwrap().clone().font, - index: 0, - tweak: egui::FontTweak { - scale: 0.88, - y_offset_factor: 0.26, - y_offset: 0.0, - }, - }); + "material".to_owned(), + egui::FontData::from_static(include_bytes!( + "../../../../fonts/material.otf" + )).tweak(egui::FontTweak { + scale: 1.0, + y_offset_factor: 0.16, + y_offset: 0.0 + }), + ); + fonts + .families + .entry(Proportional) + .or_default() + .insert(0, "material".to_owned()); fonts.font_data.insert( "noto".to_owned(), egui::FontData::from_static(include_bytes!( - "../../../../fonts/noto_light.ttf" + "../../../../fonts/noto_sc_reg.otf" )).tweak(egui::FontTweak { scale: 1.0, y_offset_factor: -0.25, y_offset: 0.0 }), ); - fonts .families .entry(Proportional) .or_default() .insert(0, "noto".to_owned()); + + ctx.set_fonts(fonts); use egui::FontId; diff --git a/src/gui/screens/account.rs b/src/gui/screens/account.rs index 164996c..af5289f 100644 --- a/src/gui/screens/account.rs +++ b/src/gui/screens/account.rs @@ -34,6 +34,7 @@ impl super::Screen for Account { fn show(&mut self, ui: &mut egui::Ui, + frame: &mut eframe::Frame, nav: &mut Navigator, cb: &dyn PlatformCallbacks) { diff --git a/src/gui/screens/accounts.rs b/src/gui/screens/accounts.rs index b733ee1..a24cf12 100644 --- a/src/gui/screens/accounts.rs +++ b/src/gui/screens/accounts.rs @@ -12,18 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::ops::{Deref, DerefMut}; use crate::gui::platform::PlatformCallbacks; use crate::gui::screens::{Navigator, Screen, ScreenId}; -use crate::gui::views::title_panel::TitlePanel; +use crate::gui::{SYM_ACCOUNTS, SYM_ARROW_BACK, SYM_NETWORK, SYM_SETTINGS}; +use crate::gui::screens::root::dual_panel_mode; +use crate::gui::views::title_panel::{PanelAction, TitlePanel}; use crate::gui::views::View; -#[derive(Default)] pub struct Accounts { title: String, } -impl Accounts { - pub(crate) fn new() -> Self { +impl Default for Accounts { + fn default() -> Self { Self { title: t!("accounts"), } @@ -37,14 +39,40 @@ impl Screen for Accounts { fn show(&mut self, ui: &mut egui::Ui, + frame: &mut eframe::Frame, nav: &mut Navigator, cb: &dyn PlatformCallbacks) { + let Self { title } = self; + TitlePanel::default() - .title(self.title.to_owned()) - .ui(ui); - if ui.button("test").clicked() { + .title(title.to_owned()) + .left_action(if !dual_panel_mode(frame) { + Some(PanelAction { + icon: SYM_NETWORK.into(), + on_click: Box::new(on_left_click), + }) + } else { + None + }) + .right_action(Some(PanelAction { + icon: SYM_SETTINGS.into(), + on_click: Box::new(on_right_click), + })) + .ui(ui, &mut Some(nav)); + ui.label(format!("{}Here we go 10000 ツ", SYM_ARROW_BACK)); + if ui.button("TEST").clicked() { + nav.to(ScreenId::Account) + }; + if ui.button(format!("{}BACK ", SYM_ARROW_BACK)).clicked() { nav.to(ScreenId::Account) }; } +} +fn on_left_click(nav: &mut Option<&mut Navigator>) { + nav.as_mut().unwrap().toggle_left_panel(); +} + +fn on_right_click(nav: &mut Option<&mut Navigator>) { + nav.as_mut().unwrap().toggle_left_panel(); } \ No newline at end of file diff --git a/src/gui/screens/mod.rs b/src/gui/screens/mod.rs index d2ca610..384c6c3 100644 --- a/src/gui/screens/mod.rs +++ b/src/gui/screens/mod.rs @@ -19,17 +19,13 @@ pub use account::Account; use crate::gui::App; use crate::gui::platform::PlatformCallbacks; +use crate::gui::views::title_panel::PanelAction; mod navigator; mod root; mod accounts; mod account; -// pub trait TitlePanelActions { -// fn left(&self) -> Option; -// fn right(&self) -> Option; -// } - #[derive(Ord, Eq, PartialOrd, PartialEq)] pub enum ScreenId { Root, @@ -39,10 +35,9 @@ pub enum ScreenId { pub trait Screen { fn id(&self) -> ScreenId; - fn show( - &mut self, + fn show(&mut self, ui: &mut egui::Ui, + frame: &mut eframe::Frame, navigator: &mut Navigator, - cb: &dyn PlatformCallbacks - ); + cb: &dyn PlatformCallbacks); } diff --git a/src/gui/screens/navigator.rs b/src/gui/screens/navigator.rs index e12ae77..ba1cfe6 100644 --- a/src/gui/screens/navigator.rs +++ b/src/gui/screens/navigator.rs @@ -18,6 +18,7 @@ use crate::gui::screens::ScreenId; pub struct Navigator { pub(crate) stack: BTreeSet, + pub(crate) left_panel_open: bool, } impl Default for Navigator { @@ -25,7 +26,8 @@ impl Default for Navigator { let mut stack = BTreeSet::new(); stack.insert(ScreenId::Accounts); Self { - stack + stack, + left_panel_open: false } } } @@ -38,4 +40,8 @@ impl Navigator { pub fn back(&mut self) { self.stack.pop_last(); } + + pub fn toggle_left_panel(&mut self) { + self.left_panel_open = !self.left_panel_open; + } } \ No newline at end of file diff --git a/src/gui/screens/root.rs b/src/gui/screens/root.rs index e53d5f3..7699771 100644 --- a/src/gui/screens/root.rs +++ b/src/gui/screens/root.rs @@ -12,7 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::cmp::min; +use eframe::epaint::{Shadow, Stroke}; +use eframe::Frame; +use egui::style::Margin; use egui::Ui; +use crate::gui::{App, COLOR_YELLOW}; use crate::gui::platform::PlatformCallbacks; use crate::gui::screens::{Account, Accounts, Navigator, Screen, ScreenId}; @@ -24,11 +29,11 @@ pub struct Root { impl Default for Root { fn default() -> Self { Self { - navigator: Navigator::new(), + navigator: Navigator::default(), screens: (vec![ Box::new(Accounts::default()), Box::new(Account::default()) - ]) + ]), } } } @@ -38,20 +43,55 @@ impl Root { ScreenId::Root } - pub fn ui(&mut self, ui: &mut Ui, cb: &dyn PlatformCallbacks) { - self.show_current_screen(ui, cb); + pub fn ui(&mut self, ui: &mut Ui, frame: &mut Frame, cb: &dyn PlatformCallbacks) { + let is_network_panel_open = self.navigator.left_panel_open || dual_panel_mode(frame); + + egui::SidePanel::left("network_panel") + .resizable(false) + .exact_width(if dual_panel_mode(frame) { + min(frame.info().window_info.size.x as i64, 400) as f32 + } else { + frame.info().window_info.size.x + }) + .frame(egui::Frame { + inner_margin: Margin::same(0.0), + outer_margin: Margin::same(0.0), + fill: COLOR_YELLOW, + .. Default::default() + }) + .show_animated_inside(ui, is_network_panel_open, |ui| { + //TODO: Network content + ui.vertical_centered(|ui| { + ui.heading("🖧 Node"); + }); + + ui.separator(); + }); + + egui::CentralPanel::default().frame(egui::containers::Frame { + ..Default::default() + }).show_inside(ui, |ui| { + self.show_current_screen(ui, frame, cb); + }); + } - pub fn show_current_screen(&mut self, - ui: &mut Ui, - cb: &dyn PlatformCallbacks) { - let Self { navigator, screens } = self; + pub fn show_current_screen(&mut self, ui: &mut Ui, frame: &mut Frame, cb: &dyn PlatformCallbacks) { + let Self { navigator, screens, .. } = self; let current = navigator.stack.last().unwrap(); for screen in screens.iter_mut() { if screen.id() == *current { - screen.show(ui, navigator, cb); + screen.show(ui, frame, navigator, cb); break; } } } +} + +pub fn dual_panel_mode(frame: &mut Frame) -> bool { + is_landscape(frame) && frame.info().window_info.size.x > 400.0 +} + +pub fn is_landscape(frame: &mut Frame) -> bool { + return frame.info().window_info.size.x > frame.info().window_info.size.y } \ No newline at end of file diff --git a/src/gui/views/title_panel.rs b/src/gui/views/title_panel.rs index 12df641..5901954 100644 --- a/src/gui/views/title_panel.rs +++ b/src/gui/views/title_panel.rs @@ -13,15 +13,17 @@ // limitations under the License. -use egui::{Color32, RichText, Sense, Stroke, Widget}; +use eframe::epaint::text::{LayoutJob, TextFormat, TextWrapping}; +use egui::{Color32, FontId, RichText, Sense, Stroke, Widget}; use egui::style::Margin; use egui_extras::{Size, StripBuilder}; -use crate::gui::COLOR_YELLOW; +use crate::gui::{COLOR_DARK, COLOR_YELLOW}; +use crate::gui::screens::Navigator; use crate::gui::views::View; pub struct PanelAction { - icon: Box, - on_click: Box + pub(crate) icon: Box, + pub(crate) on_click: Box)>, } #[derive(Default)] @@ -42,25 +44,23 @@ impl TitlePanel { self } - pub fn left_action(mut self, action: PanelAction) -> Self { - self.actions.left = Some(action); + pub fn left_action(mut self, action: Option) -> Self { + self.actions.left = action; self } - pub fn right_action(mut self, action: PanelAction) -> Self { - self.actions.right = Some(action); + pub fn right_action(mut self, action: Option) -> Self { + self.actions.right = action; self } } -impl View for TitlePanel { - fn ui(&mut self, ui: &mut egui::Ui) { - // Disable stroke around panels - let panel_stroke_default = ui.style().visuals.widgets.noninteractive.bg_stroke; +impl TitlePanel { + pub(crate) fn ui(&mut self, ui: &mut egui::Ui, nav: &mut Option<&mut Navigator>) { + // Disable stroke around panel ui.style_mut().visuals.widgets.noninteractive.bg_stroke = Stroke::NONE; // Disable stroke around buttons on hover - let button_hover_stroke_default = ui.style().visuals.widgets.active.bg_stroke; ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE; let Self { actions, title } = self; @@ -71,30 +71,32 @@ impl View for TitlePanel { fill: COLOR_YELLOW, inner_margin: Margin::same(0.0), outer_margin: Margin::same(0.0), - rounding: Default::default(), + stroke: Stroke::NONE, ..Default::default() }) .show_inside(ui, |ui| { StripBuilder::new(ui) - .size(Size::exact(58.0)) + .size(Size::exact(52.0)) .vertical(|mut strip| { strip.strip(|builder| { builder - .size(Size::exact(58.0)) + .size(Size::exact(52.0)) .size(Size::remainder()) - .size(Size::exact(58.0)) + .size(Size::exact(52.0)) .horizontal(|mut strip| { strip.cell(|ui| { if actions.left.is_some() { let action = actions.left.as_ref().unwrap(); ui.centered_and_justified(|ui| { let b = egui::widgets::Button::new( - RichText::new(&action.icon.to_string()).size(24.0) + RichText::new(&action.icon.to_string()) + .size(24.0) + .color(COLOR_DARK) ).fill(Color32::TRANSPARENT) .ui(ui) .interact(Sense::click_and_drag()); if b.drag_released() || b.clicked() { - (action.on_click)(); + (action.on_click)(nav); }; }); } @@ -106,9 +108,7 @@ impl View for TitlePanel { strip.cell(|ui| { if title.is_some() { ui.centered_and_justified(|ui| { - ui.label(RichText::new( - title.as_ref().unwrap().to_uppercase() - ).size(20.0).color(Color32::BLACK)); + show_title(title.as_ref().unwrap(), ui); }); } }); @@ -119,11 +119,13 @@ impl View for TitlePanel { let action = actions.right.as_ref().unwrap(); ui.centered_and_justified(|ui| { let b = egui::widgets::Button::new( - RichText::new(action.icon.to_string()).size(24.0) + RichText::new(action.icon.to_string()) + .size(24.0) + .color(COLOR_DARK) ).fill(Color32::TRANSPARENT) .ui(ui).interact(Sense::click_and_drag()); if b.drag_released() || b.clicked() { - (action.on_click)(); + (action.on_click)(nav); }; }); } @@ -132,11 +134,20 @@ impl View for TitlePanel { }); }); }); - - // Enable stroke around panels - ui.style_mut().visuals.widgets.noninteractive.bg_stroke = panel_stroke_default; - - // Enable stroke around buttons on hover - ui.style_mut().visuals.widgets.active.bg_stroke = button_hover_stroke_default; } +} + +fn show_title(title: &String, ui: &mut egui::Ui) { + let mut job = LayoutJob::single_section(title.to_uppercase(), TextFormat { + font_id: FontId::proportional(20.0), + color: COLOR_DARK, + .. Default::default() + }); + job.wrap = TextWrapping { + max_rows: 1, + break_anywhere: false, + overflow_character: Option::from('â€Ķ'), + ..Default::default() + }; + ui.label(job); } \ No newline at end of file