[Add] Graph Cards, Some UI fixes [TODO] Manual closing after Agreements
screens is neccesarry
This commit is contained in:
parent
997c567c80
commit
0669b8be0a
13 changed files with 206 additions and 107 deletions
|
|
@ -1,6 +1,7 @@
|
|||
use crate::gui::elements::log_card::UiLogEntry;
|
||||
use crate::{ACTIVE_TASKS, APP_STATE, SHUTDOWN, gui::elements::log_card::UiLogEntry};
|
||||
use json::{JsonValue, object};
|
||||
use std::collections::VecDeque;
|
||||
use std::{collections::VecDeque, thread, time::Duration};
|
||||
use sysinfo::{RefreshKind, System};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
|
|
@ -138,3 +139,63 @@ impl AppState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup() {
|
||||
ACTIVE_TASKS.insert("System info loader".to_string());
|
||||
tokio::spawn(async move {
|
||||
let mut sys = System::new_with_specifics(RefreshKind::new());
|
||||
let mut last_total_received = 0u64;
|
||||
let mut last_total_transmitted = 0u64;
|
||||
let mut counter = 0.0;
|
||||
loop {
|
||||
if *SHUTDOWN.read().await {
|
||||
break;
|
||||
}
|
||||
sys.refresh_all();
|
||||
|
||||
let mut tcpu = 0;
|
||||
for cpu in sys.cpus() {
|
||||
tcpu += cpu.cpu_usage() as i64;
|
||||
tcpu /= 2;
|
||||
}
|
||||
let ram = (sys.used_memory() as f64 / sys.total_memory() as f64) * 100.0;
|
||||
|
||||
let total_received = 0u64;
|
||||
let total_transmitted = 0u64;
|
||||
|
||||
let delta_received = if last_total_received == 0 {
|
||||
0
|
||||
} else {
|
||||
total_received.saturating_sub(last_total_received)
|
||||
};
|
||||
let delta_transmitted = if last_total_transmitted == 0 {
|
||||
0
|
||||
} else {
|
||||
total_transmitted.saturating_sub(last_total_transmitted)
|
||||
};
|
||||
last_total_received = total_received;
|
||||
last_total_transmitted = total_transmitted;
|
||||
|
||||
let net_down = delta_received as f64;
|
||||
let net_up = delta_transmitted as f64;
|
||||
|
||||
{
|
||||
let mut st = APP_STATE.lock().unwrap();
|
||||
st.push_cpu((counter, tcpu as f64));
|
||||
st.push_ram((counter, ram));
|
||||
st.push_net_down((counter, net_down));
|
||||
st.push_net_up((counter, net_up));
|
||||
|
||||
st.sys_info = format!("NetDown: {} NetUp: {}", delta_received, delta_transmitted);
|
||||
}
|
||||
|
||||
counter += 1.0;
|
||||
if counter > 30.0 {
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
} else {
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
}
|
||||
ACTIVE_TASKS.remove("System info loader");
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,8 +124,14 @@ impl InteractableElement for ConsoleCard {
|
|||
fn interact(&mut self, key: KeyEvent) -> InteractionResult {
|
||||
match key.code {
|
||||
KeyCode::Enter => {
|
||||
if self.content.is_empty() {
|
||||
log!("");
|
||||
return InteractionResult::Handled;
|
||||
}
|
||||
let command = self.content.clone();
|
||||
let id = Uuid::new_v4();
|
||||
let id = id.to_string();
|
||||
let id = id.split_at(8).0;
|
||||
let task_id = format!("command_{}_{}", command, id);
|
||||
ACTIVE_TASKS.insert(task_id.clone());
|
||||
tokio::spawn(async move {
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ use ratatui::{Frame, layout::Rect, widgets::Borders};
|
|||
|
||||
use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen};
|
||||
|
||||
#[allow(unused)]
|
||||
pub trait Element: Send + Sync + Any {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
fn render(&self, f: &mut Frame, r: Rect);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub trait JoinableElement: Send + Sync + Any {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
|
@ -21,6 +24,7 @@ pub trait JoinableElement: Send + Sync + Any {
|
|||
fn set_joins(&mut self, joins: Borders);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub trait InfoElement: Send + Sync + Any {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
|
@ -30,6 +34,7 @@ pub trait InfoElement: Send + Sync + Any {
|
|||
fn get_info_screen(&self) -> Box<dyn Screen>;
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub trait InteractableElement: Send + Sync + Any {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
|
|
|||
|
|
@ -28,11 +28,19 @@ pub enum GRAPHS {
|
|||
}
|
||||
|
||||
impl GRAPHS {
|
||||
pub fn get_color(&self) -> Color {
|
||||
match self {
|
||||
GRAPHS::Ram => Color::Blue,
|
||||
GRAPHS::Cpu => Color::Red,
|
||||
GRAPHS::Ping => Color::Green,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_graph(&self) -> Vec<(f64, f64)> {
|
||||
match self {
|
||||
GRAPHS::Ram => APP_STATE.lock().unwrap().ram.clone(),
|
||||
GRAPHS::Cpu => APP_STATE.lock().unwrap().cpu.clone(),
|
||||
GRAPHS::Ping => APP_STATE.lock().unwrap().ping.clone(),
|
||||
GRAPHS::Ram => APP_STATE.lock().unwrap().with_width(28).ram.clone(),
|
||||
GRAPHS::Cpu => APP_STATE.lock().unwrap().with_width(28).cpu.clone(),
|
||||
GRAPHS::Ping => APP_STATE.lock().unwrap().with_width(28).ping.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,13 +53,13 @@ impl GRAPHS {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct GraphCard {
|
||||
ui: Arc<UI>,
|
||||
graph_type: GRAPHS,
|
||||
|
||||
focused: bool,
|
||||
pub title: String,
|
||||
color: Color,
|
||||
|
||||
borders: Borders,
|
||||
joins: Borders,
|
||||
|
|
@ -66,10 +74,9 @@ impl GraphCard {
|
|||
graph_type,
|
||||
focused: false,
|
||||
title,
|
||||
color: Color::White,
|
||||
borders: Borders::ALL,
|
||||
joins: Borders::NONE,
|
||||
open: false,
|
||||
open: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,11 +105,11 @@ impl Element for GraphCard {
|
|||
.filter(|y| *y > 0.0)
|
||||
.min_by(|a, b| a.total_cmp(b))
|
||||
.unwrap_or(0.0);
|
||||
let max_y = graph.iter().map(|(_, y)| *y).fold(f64::MIN, f64::max);
|
||||
let max_y = graph.iter().map(|(_, y)| *y).fold(-1.0, f64::max);
|
||||
|
||||
let block = Block::default()
|
||||
.title(format!(
|
||||
"─{}:─{}{}──{}/{}─MIN/MAX",
|
||||
"{}:─{}{}─{}min/{}max",
|
||||
self.title,
|
||||
graph.last().unwrap_or(&(0.0, 0.0)).1 as i64,
|
||||
unit,
|
||||
|
|
@ -127,7 +134,7 @@ impl Element for GraphCard {
|
|||
y1: 0.0,
|
||||
x2: *x,
|
||||
y2: *y,
|
||||
color: self.color,
|
||||
color: self.graph_type.get_color(),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ pub mod elements {
|
|||
}
|
||||
pub mod screens {
|
||||
pub mod main_screen;
|
||||
pub mod md_viewer;
|
||||
pub mod screens;
|
||||
pub mod terms_checker;
|
||||
pub mod terms_updater;
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ impl MainScreen {
|
|||
|
||||
let nav_grid = vec![
|
||||
vec![Some(0), Some(2)],
|
||||
vec![Some(1), Some(3)],
|
||||
vec![None, Some(4)],
|
||||
vec![Some(0), Some(3)],
|
||||
vec![Some(1), Some(4)],
|
||||
];
|
||||
|
||||
let mut log_card = LogCard::new();
|
||||
|
|
@ -44,10 +44,10 @@ impl MainScreen {
|
|||
elements.push(Box::new(log_card));
|
||||
elements.push(Box::new(console_card));
|
||||
|
||||
let mut ram_graph = GraphCard::new(ui.clone(), GRAPHS::Ram, "RAM Usage".into());
|
||||
let mut ram_graph = GraphCard::new(ui.clone(), GRAPHS::Ram, "RAM".into());
|
||||
ram_graph.set_borders(Borders::TOP.union(Borders::LEFT).union(Borders::RIGHT));
|
||||
elements.push(Box::new(ram_graph));
|
||||
let mut cpu_graph = GraphCard::new(ui.clone(), GRAPHS::Cpu, "CPU Usage".into());
|
||||
let mut cpu_graph = GraphCard::new(ui.clone(), GRAPHS::Cpu, "CPU".into());
|
||||
cpu_graph.set_borders(Borders::TOP.union(Borders::LEFT).union(Borders::RIGHT));
|
||||
cpu_graph.set_joins(Borders::TOP);
|
||||
elements.push(Box::new(cpu_graph));
|
||||
|
|
@ -87,51 +87,64 @@ impl MainScreen {
|
|||
}
|
||||
|
||||
fn navigate(&mut self, direction: NavDirection) {
|
||||
let (mut y, mut x) = self.selected_coords;
|
||||
let (current_row, current_col) = self.selected_coords;
|
||||
let current_element = self.nav_grid[current_row][current_col];
|
||||
|
||||
self.unfocus_current(y, x);
|
||||
self.unfocus_current(current_row, current_col);
|
||||
|
||||
match direction {
|
||||
NavDirection::Up => {
|
||||
if y > 0 {
|
||||
y -= 1;
|
||||
}
|
||||
let (delta_row, delta_col) = match direction {
|
||||
NavDirection::Up => (-1isize, 0),
|
||||
NavDirection::Down => (1, 0),
|
||||
NavDirection::Left => (0, -1),
|
||||
NavDirection::Right => (0, 1),
|
||||
_ => (0, 0),
|
||||
};
|
||||
|
||||
let mut next_row = current_row as isize;
|
||||
let mut next_col = current_col as isize;
|
||||
|
||||
loop {
|
||||
next_row += delta_row;
|
||||
next_col += delta_col;
|
||||
|
||||
if next_row < 0 || next_col < 0 {
|
||||
self.selected_coords = (
|
||||
(next_row - delta_row) as usize,
|
||||
(next_col - delta_col) as usize,
|
||||
);
|
||||
break;
|
||||
}
|
||||
NavDirection::Down => {
|
||||
if y < self.nav_grid.len() - 1 {
|
||||
y += 1;
|
||||
}
|
||||
let next_row_u = next_row as usize;
|
||||
let next_col_u = next_col as usize;
|
||||
|
||||
if next_row_u >= self.nav_grid.len() {
|
||||
self.selected_coords = (
|
||||
(next_row - delta_row) as usize,
|
||||
(next_col - delta_col) as usize,
|
||||
);
|
||||
break;
|
||||
}
|
||||
NavDirection::Left => {
|
||||
if x > 0 {
|
||||
x -= 1;
|
||||
|
||||
if let Some(row) = self.nav_grid.get(next_row_u) {
|
||||
if next_col_u >= row.len() {
|
||||
self.selected_coords = (
|
||||
(next_row - delta_row) as usize,
|
||||
(next_col - delta_col) as usize,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
NavDirection::Right => {
|
||||
if let Some(row) = self.nav_grid.get(y) {
|
||||
if x < row.len() - 1 {
|
||||
x += 1;
|
||||
|
||||
if let Some(next_element) = row[next_col_u] {
|
||||
if Some(next_element) != current_element {
|
||||
self.selected_coords = (next_row_u, next_col_u);
|
||||
self.focus_current();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(row) = self.nav_grid.get(y) {
|
||||
if x >= row.len() {
|
||||
x = row.len() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if self
|
||||
.nav_grid
|
||||
.get(y)
|
||||
.and_then(|r| r.get(x))
|
||||
.map_or(false, |e| e.is_some())
|
||||
{
|
||||
self.selected_coords = (y, x);
|
||||
self.focus_current();
|
||||
}
|
||||
self.focus_current();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -156,21 +169,26 @@ impl Screen for MainScreen {
|
|||
let graphs_width = if self.graphs_open { 30 } else { 2 };
|
||||
let main_width = inner.width.saturating_sub(graphs_width);
|
||||
|
||||
let chunks = Layout::default()
|
||||
let horizontal_chunks = Layout::default()
|
||||
.direction(ratatui::layout::Direction::Horizontal)
|
||||
.constraints([
|
||||
Constraint::Length(main_width),
|
||||
Constraint::Length(graphs_width),
|
||||
])
|
||||
.split(inner);
|
||||
let left_chunks =
|
||||
Layout::vertical([Constraint::Min(0), Constraint::Length(3)]).split(chunks[0]);
|
||||
|
||||
if let Some(Some(index)) = self.nav_grid.get(0).and_then(|r| r.get(0)) {
|
||||
self.elements[*index].as_element().render(f, left_chunks[0]);
|
||||
let left_area = horizontal_chunks[0];
|
||||
let right_area = horizontal_chunks[1];
|
||||
|
||||
let left_rows =
|
||||
Layout::vertical([Constraint::Min(0), Constraint::Length(3)]).split(left_area);
|
||||
|
||||
if let Some(log) = self.elements.get(0) {
|
||||
log.as_element().render(f, left_rows[0]);
|
||||
}
|
||||
if let Some(Some(index)) = self.nav_grid.get(1).and_then(|r| r.get(0)) {
|
||||
self.elements[*index].as_element().render(f, left_chunks[1]);
|
||||
|
||||
if let Some(console) = self.elements.get(1) {
|
||||
console.as_element().render(f, left_rows[1]);
|
||||
}
|
||||
|
||||
let graph_elements: Vec<_> = self
|
||||
|
|
@ -179,16 +197,18 @@ impl Screen for MainScreen {
|
|||
.filter(|el| el.as_any().is::<GraphCard>())
|
||||
.collect();
|
||||
|
||||
let graph_chunks = Layout::vertical(
|
||||
graph_elements
|
||||
.iter()
|
||||
.map(|_| Constraint::Length(chunks[1].height / graph_elements.len() as u16))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.split(chunks[1]);
|
||||
if !graph_elements.is_empty() {
|
||||
let graph_chunks = Layout::vertical(
|
||||
graph_elements
|
||||
.iter()
|
||||
.map(|_| Constraint::Ratio(1, graph_elements.len() as u32))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.split(right_area);
|
||||
|
||||
for (el, area) in graph_elements.iter().zip(graph_chunks.iter()) {
|
||||
el.as_element().render(f, *area);
|
||||
for (el, area) in graph_elements.iter().zip(graph_chunks.iter()) {
|
||||
el.as_element().render(f, *area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,11 @@ use ratatui::{
|
|||
text::{Line, Span},
|
||||
widgets::{Block, Borders, Paragraph, Wrap},
|
||||
};
|
||||
use std::{any::Any, sync::Arc, time::Duration};
|
||||
use std::{any::Any, time::Duration};
|
||||
|
||||
use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen, ui::UI};
|
||||
use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen};
|
||||
|
||||
pub struct FileViewer {
|
||||
ui: Arc<UI>,
|
||||
title: String,
|
||||
text: Vec<DisplayLine>,
|
||||
scroll: u16,
|
||||
|
|
@ -25,10 +24,6 @@ impl Screen for FileViewer {
|
|||
self
|
||||
}
|
||||
|
||||
fn get_ui(&self) -> &Arc<UI> {
|
||||
&self.ui
|
||||
}
|
||||
|
||||
fn render(&self, f: &mut Frame, rect: Rect) {
|
||||
self.draw(f, rect);
|
||||
}
|
||||
|
|
@ -54,9 +49,8 @@ impl Screen for FileViewer {
|
|||
}
|
||||
|
||||
impl FileViewer {
|
||||
pub fn new(ui: Arc<UI>, title: String, content: &str) -> Self {
|
||||
pub fn new(title: String, content: &str) -> Self {
|
||||
Self {
|
||||
ui,
|
||||
title,
|
||||
text: parse_document(content.to_owned()),
|
||||
scroll: 0,
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
use crate::{
|
||||
gui::{interaction_result::InteractionResult, screens::screens::Screen, ui::UI},
|
||||
gui::{
|
||||
interaction_result::InteractionResult,
|
||||
screens::{md_viewer::FileViewer, screens::Screen},
|
||||
ui::UI,
|
||||
},
|
||||
terms::{
|
||||
buttons::{checkbox, draw_buttons},
|
||||
consent_state::UserChoice,
|
||||
focus::Focus,
|
||||
md_viewer::FileViewer,
|
||||
terms_getter::{Type, get_link, get_terms},
|
||||
},
|
||||
};
|
||||
|
|
@ -279,12 +282,11 @@ impl Screen for TermsCheckerScreen {
|
|||
_ => None,
|
||||
};
|
||||
if let Some(terms_type) = terms_type {
|
||||
let ui = self.ui.clone();
|
||||
let fut: Pin<Box<dyn Future<Output = Box<dyn Screen>> + Send>> =
|
||||
Box::pin(async move {
|
||||
let content = get_terms(terms_type.clone()).await.unwrap();
|
||||
let screen: FileViewer =
|
||||
FileViewer::new(ui.clone(), terms_type.to_string(), &content);
|
||||
FileViewer::new(terms_type.to_string(), &content);
|
||||
Box::new(screen) as Box<dyn Screen>
|
||||
});
|
||||
InteractionResult::OpenFutureScreen { screen: fut }
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
use crate::{
|
||||
gui::{interaction_result::InteractionResult, screens::screens::Screen, ui::UI},
|
||||
gui::{
|
||||
interaction_result::InteractionResult,
|
||||
screens::{md_viewer::FileViewer, screens::Screen},
|
||||
},
|
||||
terms::{
|
||||
buttons::{checkbox, draw_buttons},
|
||||
consent_state::{UpdateDecision, UserChoice},
|
||||
doc::Doc,
|
||||
focus::Focus,
|
||||
md_viewer::FileViewer,
|
||||
terms_getter::{Type, get_link, get_terms},
|
||||
terms_getter::{Type, get_newest_link, get_terms},
|
||||
},
|
||||
};
|
||||
use chrono::{Local, TimeZone, Utc};
|
||||
|
|
@ -19,11 +21,9 @@ use ratatui::{
|
|||
widgets::{Block, Borders, Paragraph},
|
||||
};
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
pub struct TermsUpdaterScreen {
|
||||
ui: Arc<UI>,
|
||||
sender: Option<oneshot::Sender<UserChoice>>,
|
||||
|
||||
eula_needed: bool,
|
||||
|
|
@ -48,7 +48,6 @@ pub struct TermsUpdaterScreen {
|
|||
}
|
||||
impl TermsUpdaterScreen {
|
||||
pub fn new(
|
||||
ui: Arc<UI>,
|
||||
consent_eula: UpdateDecision,
|
||||
consent_tos: UpdateDecision,
|
||||
consent_pp: UpdateDecision,
|
||||
|
|
@ -87,7 +86,6 @@ impl TermsUpdaterScreen {
|
|||
|| (pp_needed && !pp_future);
|
||||
|
||||
Self {
|
||||
ui,
|
||||
sender,
|
||||
|
||||
eula_needed,
|
||||
|
|
@ -653,14 +651,10 @@ impl Screen for TermsUpdaterScreen {
|
|||
};
|
||||
|
||||
if let Some(terms_type) = terms_type {
|
||||
let ui = self.ui.clone();
|
||||
let fut = Box::pin(async move {
|
||||
let content = get_terms(terms_type.clone()).await.unwrap();
|
||||
Box::new(FileViewer::new(
|
||||
ui.clone(),
|
||||
terms_type.to_string(),
|
||||
&content,
|
||||
)) as Box<dyn Screen>
|
||||
Box::new(FileViewer::new(terms_type.to_string(), &content))
|
||||
as Box<dyn Screen>
|
||||
});
|
||||
|
||||
return InteractionResult::OpenFutureScreen { screen: fut };
|
||||
|
|
@ -670,15 +664,15 @@ impl Screen for TermsUpdaterScreen {
|
|||
}
|
||||
KeyCode::Char('l') | KeyCode::Char('L') => match self.focus {
|
||||
Focus::Eula => {
|
||||
let _ = open::that(get_link(Type::EULA));
|
||||
let _ = open::that(get_newest_link(Type::EULA));
|
||||
InteractionResult::Handled
|
||||
}
|
||||
Focus::Tos => {
|
||||
let _ = open::that(get_link(Type::TOS));
|
||||
let _ = open::that(get_newest_link(Type::TOS));
|
||||
InteractionResult::Handled
|
||||
}
|
||||
Focus::Pp => {
|
||||
let _ = open::that(get_link(Type::PP));
|
||||
let _ = open::that(get_newest_link(Type::PP));
|
||||
InteractionResult::Handled
|
||||
}
|
||||
_ => InteractionResult::Unhandled,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub static FPS: Lazy<RwLock<(f64, f64)>> = Lazy::new(|| RwLock::new((0.0, 0.0)))
|
|||
|
||||
pub struct UI {
|
||||
pub terminal: Arc<Mutex<Terminal<CrosstermBackend<Stdout>>>>,
|
||||
screen: Arc<RwLock<Option<Box<dyn Screen>>>>,
|
||||
screen_stack: Arc<RwLock<Vec<Box<dyn Screen>>>>,
|
||||
}
|
||||
|
||||
pub fn start_tui() -> Arc<UI> {
|
||||
|
|
@ -111,18 +111,22 @@ impl UI {
|
|||
let terminal = init();
|
||||
Self {
|
||||
terminal: Arc::new(Mutex::new(terminal)),
|
||||
screen: Arc::new(RwLock::new(None)),
|
||||
screen_stack: Arc::new(RwLock::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_screen(&self, screen: Box<dyn Screen>) {
|
||||
*self.screen.write().await = Some(screen);
|
||||
self.screen_stack.write().await.push(screen);
|
||||
}
|
||||
pub async fn replace_screen(&self, screen: Box<dyn Screen>) {
|
||||
let mut stack = self.screen_stack.write().await;
|
||||
stack.pop();
|
||||
stack.push(screen);
|
||||
}
|
||||
|
||||
pub async fn handle_input(self: Arc<Self>, key_event: KeyEvent) {
|
||||
let result = {
|
||||
let mut guard = self.screen.write().await;
|
||||
if let Some(screen) = guard.as_mut() {
|
||||
let mut stack = self.screen_stack.write().await;
|
||||
if let Some(screen) = stack.last_mut() {
|
||||
screen.handle_input(key_event)
|
||||
} else {
|
||||
return;
|
||||
|
|
@ -138,7 +142,12 @@ impl UI {
|
|||
ui.set_screen(screen).await;
|
||||
}
|
||||
InteractionResult::CloseScreen => {
|
||||
*self.screen.write().await = None;
|
||||
let mut stack = self.screen_stack.write().await;
|
||||
stack.pop();
|
||||
|
||||
if stack.is_empty() {
|
||||
*SHUTDOWN.write().await = true;
|
||||
}
|
||||
}
|
||||
InteractionResult::Handled => {}
|
||||
InteractionResult::Unhandled => {}
|
||||
|
|
@ -146,7 +155,7 @@ impl UI {
|
|||
}
|
||||
|
||||
pub async fn render(&self) {
|
||||
if let Some(screen) = self.screen.read().await.as_ref() {
|
||||
if let Some(screen) = self.screen_stack.read().await.last() {
|
||||
let mut terminal = self.terminal.lock().unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ mod util;
|
|||
|
||||
use crate::communities::community_manager;
|
||||
use crate::communities::interactables::registry;
|
||||
use crate::gui::app_state;
|
||||
use crate::gui::app_state::AppState;
|
||||
use crate::gui::screens::main_screen::MainScreen;
|
||||
use crate::gui::ui::start_tui;
|
||||
|
|
@ -78,6 +79,7 @@ async fn main() {
|
|||
println!("You can find this at 'agreements'!");
|
||||
return;
|
||||
}
|
||||
app_state::setup();
|
||||
|
||||
let main_screen = MainScreen::new(ui.clone()).await;
|
||||
ui.set_screen(Box::new(main_screen)).await;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ async fn ensure_initial_consent(ui: Arc<UI>, state: &mut ConsentState) -> Result
|
|||
}
|
||||
}
|
||||
|
||||
&state.save_state();
|
||||
let _ = &state.save_state();
|
||||
Ok(())
|
||||
}
|
||||
UserChoice::Deny => Err(()),
|
||||
|
|
@ -77,7 +77,6 @@ async fn ensure_updates(ui: Arc<UI>, state: &mut ConsentState) -> Result<(), ()>
|
|||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
ui.set_screen(Box::new(TermsUpdaterScreen::new(
|
||||
ui.clone(),
|
||||
eula_update.clone(),
|
||||
tos_update.clone(),
|
||||
privacy_update.clone(),
|
||||
|
|
|
|||
|
|
@ -2,5 +2,4 @@ pub mod buttons;
|
|||
pub mod consent_state;
|
||||
pub mod doc;
|
||||
pub mod focus;
|
||||
pub mod md_viewer;
|
||||
pub mod terms_getter;
|
||||
|
|
|
|||
Loading…
Reference in a new issue