diff --git a/app/src/main/java/mw/gri/android/MainActivity.java b/app/src/main/java/mw/gri/android/MainActivity.java index 1dd8342..f6a7251 100644 --- a/app/src/main/java/mw/gri/android/MainActivity.java +++ b/app/src/main/java/mw/gri/android/MainActivity.java @@ -4,6 +4,8 @@ import android.os.Bundle; import android.os.Process; import android.system.ErrnoException; import android.system.Os; +import android.util.Log; +import android.view.KeyEvent; import com.google.androidgamesdk.GameActivity; public class MainActivity extends GameActivity { @@ -45,4 +47,15 @@ public class MainActivity extends GameActivity { BackgroundService.stop(getApplicationContext()); finish(); } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + onBackButtonPress(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + public native void onBackButtonPress(); } \ No newline at end of file diff --git a/src/gui/screens/account.rs b/src/gui/screens/account.rs index a6d397b..d12fa71 100644 --- a/src/gui/screens/account.rs +++ b/src/gui/screens/account.rs @@ -35,7 +35,6 @@ impl super::Screen for Account { fn ui(&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 5862819..d9c11d8 100644 --- a/src/gui/screens/accounts.rs +++ b/src/gui/screens/accounts.rs @@ -31,25 +31,19 @@ impl Screen for Accounts { fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, - nav: &mut Navigator, cb: &dyn PlatformCallbacks) { - let mut panel: TitlePanel = TitlePanel::new(nav) - .title(t!("accounts")) - .right_action(TitlePanelAction { - icon: GEAR_SIX.into(), - on_click: Box::new(|nav| { - //TODO: open settings - }), - }); - if !is_dual_panel_mode(frame) { - panel = panel.left_action(TitlePanelAction { - icon: GLOBE.into(), - on_click: Box::new(|nav|{ - nav.toggle_left_panel(); - }), - }); - } - panel.ui(ui); + TitlePanel::new(t!("accounts")) + .left_action( + if !is_dual_panel_mode(frame) { + TitlePanelAction::new(GLOBE.into(), || { + Navigator::toggle_side_panel(); + }) + } else { + None + } + ).right_action(TitlePanelAction::new(GEAR_SIX.into(), || { + //TODO: settings + })).ui(ui); egui::CentralPanel::default().frame(Frame { stroke: View::DEFAULT_STROKE, @@ -57,10 +51,10 @@ impl Screen for Accounts { }).show_inside(ui, |ui| { ui.label(format!("{}Here we go 10000 ツ", ARROW_CIRCLE_LEFT)); if ui.button("TEST").clicked() { - nav.to(ScreenId::Account) + Navigator::to(ScreenId::Account) }; if ui.button(format!("{}BACK ", ARROW_CIRCLE_LEFT)).clicked() { - nav.to(ScreenId::Account) + Navigator::to(ScreenId::Account) }; }); } diff --git a/src/gui/screens/mod.rs b/src/gui/screens/mod.rs index 7287aa7..b10c139 100644 --- a/src/gui/screens/mod.rs +++ b/src/gui/screens/mod.rs @@ -35,6 +35,5 @@ pub trait Screen { fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, - navigator: &mut Navigator, cb: &dyn PlatformCallbacks); } diff --git a/src/gui/screens/navigator.rs b/src/gui/screens/navigator.rs index 4413d87..7977d9c 100644 --- a/src/gui/screens/navigator.rs +++ b/src/gui/screens/navigator.rs @@ -13,39 +13,66 @@ // limitations under the License. use std::collections::BTreeSet; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::RwLock; + +use lazy_static::lazy_static; use crate::gui::screens::ScreenId; +lazy_static! { + static ref NAVIGATOR_STATE: RwLock = RwLock::new(Navigator::default()); +} + pub struct Navigator { - stack: BTreeSet, - pub(crate) left_panel_open: bool, + screens_stack: BTreeSet, + side_panel_open: AtomicBool, } impl Default for Navigator { fn default() -> Self { - let mut stack = BTreeSet::new(); - stack.insert(ScreenId::Accounts); Self { - stack, - left_panel_open: false + screens_stack: BTreeSet::new(), + side_panel_open: AtomicBool::new(false) } } } impl Navigator { - pub fn current(&mut self) -> &ScreenId { - self.stack.last().unwrap() + pub fn init(from: ScreenId) { + let mut w_nav = NAVIGATOR_STATE.write().unwrap(); + w_nav.screens_stack.clear(); + w_nav.screens_stack.insert(from); } - pub fn to(&mut self, id: ScreenId) { - self.stack.insert(id); + pub fn is_current(id: &ScreenId) -> bool { + let r_nav = NAVIGATOR_STATE.read().unwrap(); + r_nav.screens_stack.last().unwrap() == id } - pub fn back(&mut self) { - self.stack.pop_last(); + pub fn to(id: ScreenId) { + NAVIGATOR_STATE.write().unwrap().screens_stack.insert(id); } - pub fn toggle_left_panel(&mut self) { - self.left_panel_open = !self.left_panel_open; + pub fn back() { + let mut w_nav = NAVIGATOR_STATE.write().unwrap(); + if w_nav.screens_stack.len() > 1 { + w_nav.screens_stack.pop_last(); + } else { + + } } -} \ No newline at end of file + + pub fn toggle_side_panel() { + let w_nav = NAVIGATOR_STATE.write().unwrap(); + w_nav.side_panel_open.store( + !w_nav.side_panel_open.load(Ordering::Relaxed), + Ordering::Relaxed + ); + } + + pub fn is_side_panel_open() -> bool { + let r_nav = NAVIGATOR_STATE.read().unwrap(); + r_nav.side_panel_open.load(Ordering::Relaxed) + } +} diff --git a/src/gui/screens/root.rs b/src/gui/screens/root.rs index 91ddd54..7b94650 100644 --- a/src/gui/screens/root.rs +++ b/src/gui/screens/root.rs @@ -20,15 +20,15 @@ use crate::gui::screens::{Account, Accounts, Navigator, Screen, ScreenId}; use crate::gui::views::Network; pub struct Root { - navigator: Navigator, screens: Vec>, network: Network } impl Default for Root { fn default() -> Self { + Navigator::init_from(ScreenId::Accounts); + Self { - navigator: Navigator::default(), screens: (vec![ Box::new(Accounts::default()), Box::new(Account::default()) @@ -40,7 +40,7 @@ impl Default for Root { impl Root { pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) { - let is_network_panel_open = self.navigator.left_panel_open || is_dual_panel_mode(frame); + let is_network_panel_open = Navigator::is_side_panel_open() || is_dual_panel_mode(frame); egui::SidePanel::left("network_panel") .resizable(false) @@ -53,7 +53,7 @@ impl Root { .. Default::default() }) .show_animated_inside(ui, is_network_panel_open, |ui| { - self.network.ui(ui, frame, &mut self.navigator, cb); + self.network.ui(ui, frame, cb); }); egui::CentralPanel::default().frame(egui::Frame { @@ -68,13 +68,24 @@ impl Root { ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) { - let Self { navigator, screens, .. } = self; - let current = navigator.current(); + let Self { screens, .. } = self; for screen in screens.iter_mut() { - if screen.id() == *current { - screen.ui(ui, frame, navigator, cb); + if Navigator::is_current(&screen.id()) { + screen.ui(ui, frame, cb); break; } } } +} + +#[allow(dead_code)] +#[cfg(target_os = "android")] +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn Java_mw_gri_android_MainActivity_onBackButtonPress( + _env: jni::JNIEnv, + _class: jni::objects::JObject, + _activity: jni::objects::JObject, +) { + Navigator::back(); } \ No newline at end of file diff --git a/src/gui/views/network.rs b/src/gui/views/network.rs index e9b88d9..0ea03c8 100644 --- a/src/gui/views/network.rs +++ b/src/gui/views/network.rs @@ -63,7 +63,6 @@ impl Network { pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, - nav: &mut Navigator, _: &dyn PlatformCallbacks) { egui::TopBottomPanel::top("network_title") @@ -76,7 +75,7 @@ impl Network { ..Default::default() }) .show_inside(ui, |ui| { - self.draw_title(ui, frame, nav); + self.draw_title(ui, frame); }); egui::TopBottomPanel::bottom("network_tabs") @@ -145,10 +144,7 @@ impl Network { } } - fn draw_title(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, nav: &mut Navigator) { - // Disable stroke around title buttons on hover - ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE; - + fn draw_title(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) { StripBuilder::new(ui) .size(Size::exact(52.0)) .vertical(|mut strip| { @@ -172,7 +168,7 @@ impl Network { if !is_dual_panel_mode(frame) { ui.centered_and_justified(|ui| { View::title_button(ui, CARDHOLDER, || { - nav.toggle_left_panel(); + Navigator::toggle_side_panel(); }); }); } diff --git a/src/gui/views/network_node.rs b/src/gui/views/network_node.rs index 6f73129..6a65c16 100644 --- a/src/gui/views/network_node.rs +++ b/src/gui/views/network_node.rs @@ -163,7 +163,6 @@ impl NetworkTab for NetworkNode { [false, false, true, false]); }); columns[1].vertical_centered(|ui| { - let ts = stats.chain_stats.latest_timestamp; View::rounded_box(ui, stats.peer_count.to_string(), t!("peers"), diff --git a/src/gui/views/title_panel.rs b/src/gui/views/title_panel.rs index 6211536..7e4a96f 100644 --- a/src/gui/views/title_panel.rs +++ b/src/gui/views/title_panel.rs @@ -23,7 +23,13 @@ use crate::gui::views::View; pub struct TitlePanelAction { pub(crate) icon: Box, - pub(crate) on_click: Box, + pub(crate) on_click: Box, +} + +impl TitlePanelAction { + pub fn new(icon: Box, on_click: fn()) -> Option { + Option::from(Self { icon, on_click: Box::new(on_click) }) + } } #[derive(Default)] @@ -32,41 +38,31 @@ pub struct TitlePanelActions { right: Option } -pub struct TitlePanel<'nav> { - title: Option, +pub struct TitlePanel { + title: String, actions: TitlePanelActions, - nav: &'nav mut Navigator } -impl<'nav> TitlePanel<'nav> { - pub fn new(nav: &'nav mut Navigator) -> TitlePanel<'nav> { +impl TitlePanel { + pub fn new(title: String) -> Self { Self { - title: None, - actions: Default::default(), - nav, + title, + actions: TitlePanelActions::default() } } - pub fn title(mut self, title: String) -> Self { - self.title = Some(title); + pub fn left_action(mut self, action: Option) -> Self { + self.actions.left = action; self } - pub fn left_action(mut self, action: TitlePanelAction) -> Self { - self.actions.left = Some(action); - self - } - - pub fn right_action(mut self, action: TitlePanelAction) -> Self { - self.actions.right = Some(action); + pub fn right_action(mut self, action: Option) -> Self { + self.actions.right = action; self } pub fn ui(&mut self, ui: &mut egui::Ui) { - // Disable stroke around panel buttons on hover - ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE; - - let Self { actions, title, nav } = self; + let Self { actions, title } = self; egui::TopBottomPanel::top("title_panel") .resizable(false) @@ -88,19 +84,19 @@ impl<'nav> TitlePanel<'nav> { .size(Size::exact(52.0)) .horizontal(|mut strip| { strip.cell(|ui| { - show_action(ui, actions.left.as_ref(), nav); + show_action(ui, actions.left.as_ref()); }); strip.strip(|builder| { builder .size(Size::remainder()) .vertical(|mut strip| { strip.cell(|ui| { - show_title(&*title, ui); + show_title(title, ui); }); }); }); strip.cell(|ui| { - show_action(ui, actions.right.as_ref(), nav); + show_action(ui, actions.right.as_ref()); }); }); }); @@ -109,35 +105,32 @@ impl<'nav> TitlePanel<'nav> { } } -fn show_action(ui: &mut egui::Ui, action: Option<&TitlePanelAction>, navigator: &mut Navigator) { +fn show_action(ui: &mut egui::Ui, action: Option<&TitlePanelAction>) { if action.is_some() { let action = action.unwrap(); ui.centered_and_justified(|ui| { View::title_button(ui, &action.icon, || { - (action.on_click)(navigator); + (action.on_click)(); }); }); } } -fn show_title(title: &Option, ui: &mut egui::Ui) { - if title.is_some() { - ui.centered_and_justified(|ui| { - let title_text = title.as_ref().unwrap().to_uppercase(); - let mut job = LayoutJob::single_section(title_text, 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); - +fn show_title(title: &String, ui: &mut egui::Ui) { + ui.centered_and_justified(|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); + + }); } diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index 5c3645b..dfafc57 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -24,15 +24,20 @@ impl View { pub const DEFAULT_STROKE: Stroke = Stroke { width: 1.0, color: Color32::from_gray(190) }; pub fn title_button(ui: &mut egui::Ui, icon: &str, action: impl FnOnce()) { - let b = egui::widgets::Button::new( - RichText::new(icon.to_string()).size(24.0).color(COLOR_DARK) - ).fill(Color32::TRANSPARENT) - .ui(ui).interact(Sense::click_and_drag()); + ui.scope(|ui| { + // Disable stroke around title buttons on hover + ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE; - // Click optimization for touch screens - if b.drag_released() || b.clicked() { - (action)(); - }; + let b = egui::widgets::Button::new( + RichText::new(icon.to_string()).size(24.0).color(COLOR_DARK) + ).fill(Color32::TRANSPARENT) + .ui(ui).interact(Sense::click_and_drag()); + + // Click optimization for touch screens + if b.drag_released() || b.clicked() { + (action)(); + }; + }); } pub fn tab_button(ui: &mut egui::Ui, icon: &str, active: bool, mut action: impl FnMut()) { @@ -53,11 +58,6 @@ impl View { .fill(color) .ui(ui).interact(Sense::click_and_drag()); - - let vel_y = ui.ctx().input().pointer.delta().y; - let vel_x = ui.ctx().input().pointer.delta().x; - println!("12345, vel {}, {}", vel_y, vel_x); - // Click optimization for touch screens if b.drag_released() || b.clicked() { (action)();