[Add] Graph Cards, Some UI fixes [TODO] Manual closing after Agreements

screens is neccesarry
This commit is contained in:
Alex Emmet 2026-02-21 13:18:59 +01:00
commit 0669b8be0a
13 changed files with 206 additions and 107 deletions

View file

@ -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 json::{JsonValue, object};
use std::collections::VecDeque; use std::{collections::VecDeque, thread, time::Duration};
use sysinfo::{RefreshKind, System};
#[derive(Clone)] #[derive(Clone)]
pub struct AppState { 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");
});
}

View file

@ -124,8 +124,14 @@ impl InteractableElement for ConsoleCard {
fn interact(&mut self, key: KeyEvent) -> InteractionResult { fn interact(&mut self, key: KeyEvent) -> InteractionResult {
match key.code { match key.code {
KeyCode::Enter => { KeyCode::Enter => {
if self.content.is_empty() {
log!("");
return InteractionResult::Handled;
}
let command = self.content.clone(); let command = self.content.clone();
let id = Uuid::new_v4(); let id = Uuid::new_v4();
let id = id.to_string();
let id = id.split_at(8).0;
let task_id = format!("command_{}_{}", command, id); let task_id = format!("command_{}_{}", command, id);
ACTIVE_TASKS.insert(task_id.clone()); ACTIVE_TASKS.insert(task_id.clone());
tokio::spawn(async move { tokio::spawn(async move {

View file

@ -5,12 +5,15 @@ use ratatui::{Frame, layout::Rect, widgets::Borders};
use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen}; use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen};
#[allow(unused)]
pub trait Element: Send + Sync + Any { pub trait Element: Send + Sync + Any {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any;
fn render(&self, f: &mut Frame, r: Rect); fn render(&self, f: &mut Frame, r: Rect);
} }
#[allow(unused)]
pub trait JoinableElement: Send + Sync + Any { pub trait JoinableElement: Send + Sync + Any {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut 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); fn set_joins(&mut self, joins: Borders);
} }
#[allow(unused)]
pub trait InfoElement: Send + Sync + Any { pub trait InfoElement: Send + Sync + Any {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut 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>; fn get_info_screen(&self) -> Box<dyn Screen>;
} }
#[allow(unused)]
pub trait InteractableElement: Send + Sync + Any { pub trait InteractableElement: Send + Sync + Any {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any;

View file

@ -28,11 +28,19 @@ pub enum GRAPHS {
} }
impl 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)> { pub fn get_graph(&self) -> Vec<(f64, f64)> {
match self { match self {
GRAPHS::Ram => APP_STATE.lock().unwrap().ram.clone(), GRAPHS::Ram => APP_STATE.lock().unwrap().with_width(28).ram.clone(),
GRAPHS::Cpu => APP_STATE.lock().unwrap().cpu.clone(), GRAPHS::Cpu => APP_STATE.lock().unwrap().with_width(28).cpu.clone(),
GRAPHS::Ping => APP_STATE.lock().unwrap().ping.clone(), GRAPHS::Ping => APP_STATE.lock().unwrap().with_width(28).ping.clone(),
} }
} }
@ -45,13 +53,13 @@ impl GRAPHS {
} }
} }
#[allow(unused)]
pub struct GraphCard { pub struct GraphCard {
ui: Arc<UI>, ui: Arc<UI>,
graph_type: GRAPHS, graph_type: GRAPHS,
focused: bool, focused: bool,
pub title: String, pub title: String,
color: Color,
borders: Borders, borders: Borders,
joins: Borders, joins: Borders,
@ -66,10 +74,9 @@ impl GraphCard {
graph_type, graph_type,
focused: false, focused: false,
title, title,
color: Color::White,
borders: Borders::ALL, borders: Borders::ALL,
joins: Borders::NONE, joins: Borders::NONE,
open: false, open: true,
} }
} }
@ -98,11 +105,11 @@ impl Element for GraphCard {
.filter(|y| *y > 0.0) .filter(|y| *y > 0.0)
.min_by(|a, b| a.total_cmp(b)) .min_by(|a, b| a.total_cmp(b))
.unwrap_or(0.0); .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() let block = Block::default()
.title(format!( .title(format!(
"─{}:─{}{}──{}/{}─MIN/MAX", "{}:─{}{}─{}min/{}max",
self.title, self.title,
graph.last().unwrap_or(&(0.0, 0.0)).1 as i64, graph.last().unwrap_or(&(0.0, 0.0)).1 as i64,
unit, unit,
@ -127,7 +134,7 @@ impl Element for GraphCard {
y1: 0.0, y1: 0.0,
x2: *x, x2: *x,
y2: *y, y2: *y,
color: self.color, color: self.graph_type.get_color(),
}); });
} }
}); });

View file

@ -6,6 +6,7 @@ pub mod elements {
} }
pub mod screens { pub mod screens {
pub mod main_screen; pub mod main_screen;
pub mod md_viewer;
pub mod screens; pub mod screens;
pub mod terms_checker; pub mod terms_checker;
pub mod terms_updater; pub mod terms_updater;

View file

@ -32,8 +32,8 @@ impl MainScreen {
let nav_grid = vec![ let nav_grid = vec![
vec![Some(0), Some(2)], vec![Some(0), Some(2)],
vec![Some(1), Some(3)], vec![Some(0), Some(3)],
vec![None, Some(4)], vec![Some(1), Some(4)],
]; ];
let mut log_card = LogCard::new(); let mut log_card = LogCard::new();
@ -44,10 +44,10 @@ impl MainScreen {
elements.push(Box::new(log_card)); elements.push(Box::new(log_card));
elements.push(Box::new(console_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)); ram_graph.set_borders(Borders::TOP.union(Borders::LEFT).union(Borders::RIGHT));
elements.push(Box::new(ram_graph)); 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_borders(Borders::TOP.union(Borders::LEFT).union(Borders::RIGHT));
cpu_graph.set_joins(Borders::TOP); cpu_graph.set_joins(Borders::TOP);
elements.push(Box::new(cpu_graph)); elements.push(Box::new(cpu_graph));
@ -87,52 +87,65 @@ impl MainScreen {
} }
fn navigate(&mut self, direction: NavDirection) { 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 { let (delta_row, delta_col) = match direction {
NavDirection::Up => { NavDirection::Up => (-1isize, 0),
if y > 0 { NavDirection::Down => (1, 0),
y -= 1; 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;
} }
} let next_row_u = next_row as usize;
NavDirection::Down => { let next_col_u = next_col as usize;
if y < self.nav_grid.len() - 1 {
y += 1; if next_row_u >= self.nav_grid.len() {
} self.selected_coords = (
} (next_row - delta_row) as usize,
NavDirection::Left => { (next_col - delta_col) as usize,
if x > 0 { );
x -= 1; break;
}
}
NavDirection::Right => {
if let Some(row) = self.nav_grid.get(y) {
if x < row.len() - 1 {
x += 1;
}
}
}
_ => {}
} }
if let Some(row) = self.nav_grid.get(y) { if let Some(row) = self.nav_grid.get(next_row_u) {
if x >= row.len() { if next_col_u >= row.len() {
x = row.len() - 1; self.selected_coords = (
} (next_row - delta_row) as usize,
(next_col - delta_col) as usize,
);
break;
} }
if self if let Some(next_element) = row[next_col_u] {
.nav_grid if Some(next_element) != current_element {
.get(y) self.selected_coords = (next_row_u, next_col_u);
.and_then(|r| r.get(x))
.map_or(false, |e| e.is_some())
{
self.selected_coords = (y, x);
self.focus_current(); self.focus_current();
return;
} }
} }
}
}
self.focus_current();
}
} }
impl Screen for MainScreen { impl Screen for MainScreen {
@ -156,21 +169,26 @@ impl Screen for MainScreen {
let graphs_width = if self.graphs_open { 30 } else { 2 }; let graphs_width = if self.graphs_open { 30 } else { 2 };
let main_width = inner.width.saturating_sub(graphs_width); let main_width = inner.width.saturating_sub(graphs_width);
let chunks = Layout::default() let horizontal_chunks = Layout::default()
.direction(ratatui::layout::Direction::Horizontal) .direction(ratatui::layout::Direction::Horizontal)
.constraints([ .constraints([
Constraint::Length(main_width), Constraint::Length(main_width),
Constraint::Length(graphs_width), Constraint::Length(graphs_width),
]) ])
.split(inner); .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)) { let left_area = horizontal_chunks[0];
self.elements[*index].as_element().render(f, left_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 let graph_elements: Vec<_> = self
@ -179,18 +197,20 @@ impl Screen for MainScreen {
.filter(|el| el.as_any().is::<GraphCard>()) .filter(|el| el.as_any().is::<GraphCard>())
.collect(); .collect();
if !graph_elements.is_empty() {
let graph_chunks = Layout::vertical( let graph_chunks = Layout::vertical(
graph_elements graph_elements
.iter() .iter()
.map(|_| Constraint::Length(chunks[1].height / graph_elements.len() as u16)) .map(|_| Constraint::Ratio(1, graph_elements.len() as u32))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
.split(chunks[1]); .split(right_area);
for (el, area) in graph_elements.iter().zip(graph_chunks.iter()) { for (el, area) in graph_elements.iter().zip(graph_chunks.iter()) {
el.as_element().render(f, *area); el.as_element().render(f, *area);
} }
} }
}
fn handle_input(&mut self, event: KeyEvent) -> InteractionResult { fn handle_input(&mut self, event: KeyEvent) -> InteractionResult {
match event.code { match event.code {

View file

@ -5,12 +5,11 @@ use ratatui::{
text::{Line, Span}, text::{Line, Span},
widgets::{Block, Borders, Paragraph, Wrap}, 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 { pub struct FileViewer {
ui: Arc<UI>,
title: String, title: String,
text: Vec<DisplayLine>, text: Vec<DisplayLine>,
scroll: u16, scroll: u16,
@ -25,10 +24,6 @@ impl Screen for FileViewer {
self self
} }
fn get_ui(&self) -> &Arc<UI> {
&self.ui
}
fn render(&self, f: &mut Frame, rect: Rect) { fn render(&self, f: &mut Frame, rect: Rect) {
self.draw(f, rect); self.draw(f, rect);
} }
@ -54,9 +49,8 @@ impl Screen for FileViewer {
} }
impl FileViewer { impl FileViewer {
pub fn new(ui: Arc<UI>, title: String, content: &str) -> Self { pub fn new(title: String, content: &str) -> Self {
Self { Self {
ui,
title, title,
text: parse_document(content.to_owned()), text: parse_document(content.to_owned()),
scroll: 0, scroll: 0,

View file

@ -1,10 +1,13 @@
use crate::{ use crate::{
gui::{interaction_result::InteractionResult, screens::screens::Screen, ui::UI}, gui::{
interaction_result::InteractionResult,
screens::{md_viewer::FileViewer, screens::Screen},
ui::UI,
},
terms::{ terms::{
buttons::{checkbox, draw_buttons}, buttons::{checkbox, draw_buttons},
consent_state::UserChoice, consent_state::UserChoice,
focus::Focus, focus::Focus,
md_viewer::FileViewer,
terms_getter::{Type, get_link, get_terms}, terms_getter::{Type, get_link, get_terms},
}, },
}; };
@ -279,12 +282,11 @@ impl Screen for TermsCheckerScreen {
_ => None, _ => None,
}; };
if let Some(terms_type) = terms_type { if let Some(terms_type) = terms_type {
let ui = self.ui.clone();
let fut: Pin<Box<dyn Future<Output = Box<dyn Screen>> + Send>> = let fut: Pin<Box<dyn Future<Output = Box<dyn Screen>> + Send>> =
Box::pin(async move { Box::pin(async move {
let content = get_terms(terms_type.clone()).await.unwrap(); let content = get_terms(terms_type.clone()).await.unwrap();
let screen: FileViewer = 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> Box::new(screen) as Box<dyn Screen>
}); });
InteractionResult::OpenFutureScreen { screen: fut } InteractionResult::OpenFutureScreen { screen: fut }

View file

@ -1,12 +1,14 @@
use crate::{ use crate::{
gui::{interaction_result::InteractionResult, screens::screens::Screen, ui::UI}, gui::{
interaction_result::InteractionResult,
screens::{md_viewer::FileViewer, screens::Screen},
},
terms::{ terms::{
buttons::{checkbox, draw_buttons}, buttons::{checkbox, draw_buttons},
consent_state::{UpdateDecision, UserChoice}, consent_state::{UpdateDecision, UserChoice},
doc::Doc, doc::Doc,
focus::Focus, focus::Focus,
md_viewer::FileViewer, terms_getter::{Type, get_newest_link, get_terms},
terms_getter::{Type, get_link, get_terms},
}, },
}; };
use chrono::{Local, TimeZone, Utc}; use chrono::{Local, TimeZone, Utc};
@ -19,11 +21,9 @@ use ratatui::{
widgets::{Block, Borders, Paragraph}, widgets::{Block, Borders, Paragraph},
}; };
use std::any::Any; use std::any::Any;
use std::sync::Arc;
use tokio::sync::oneshot; use tokio::sync::oneshot;
pub struct TermsUpdaterScreen { pub struct TermsUpdaterScreen {
ui: Arc<UI>,
sender: Option<oneshot::Sender<UserChoice>>, sender: Option<oneshot::Sender<UserChoice>>,
eula_needed: bool, eula_needed: bool,
@ -48,7 +48,6 @@ pub struct TermsUpdaterScreen {
} }
impl TermsUpdaterScreen { impl TermsUpdaterScreen {
pub fn new( pub fn new(
ui: Arc<UI>,
consent_eula: UpdateDecision, consent_eula: UpdateDecision,
consent_tos: UpdateDecision, consent_tos: UpdateDecision,
consent_pp: UpdateDecision, consent_pp: UpdateDecision,
@ -87,7 +86,6 @@ impl TermsUpdaterScreen {
|| (pp_needed && !pp_future); || (pp_needed && !pp_future);
Self { Self {
ui,
sender, sender,
eula_needed, eula_needed,
@ -653,14 +651,10 @@ impl Screen for TermsUpdaterScreen {
}; };
if let Some(terms_type) = terms_type { if let Some(terms_type) = terms_type {
let ui = self.ui.clone();
let fut = Box::pin(async move { let fut = Box::pin(async move {
let content = get_terms(terms_type.clone()).await.unwrap(); let content = get_terms(terms_type.clone()).await.unwrap();
Box::new(FileViewer::new( Box::new(FileViewer::new(terms_type.to_string(), &content))
ui.clone(), as Box<dyn Screen>
terms_type.to_string(),
&content,
)) as Box<dyn Screen>
}); });
return InteractionResult::OpenFutureScreen { screen: fut }; return InteractionResult::OpenFutureScreen { screen: fut };
@ -670,15 +664,15 @@ impl Screen for TermsUpdaterScreen {
} }
KeyCode::Char('l') | KeyCode::Char('L') => match self.focus { KeyCode::Char('l') | KeyCode::Char('L') => match self.focus {
Focus::Eula => { Focus::Eula => {
let _ = open::that(get_link(Type::EULA)); let _ = open::that(get_newest_link(Type::EULA));
InteractionResult::Handled InteractionResult::Handled
} }
Focus::Tos => { Focus::Tos => {
let _ = open::that(get_link(Type::TOS)); let _ = open::that(get_newest_link(Type::TOS));
InteractionResult::Handled InteractionResult::Handled
} }
Focus::Pp => { Focus::Pp => {
let _ = open::that(get_link(Type::PP)); let _ = open::that(get_newest_link(Type::PP));
InteractionResult::Handled InteractionResult::Handled
} }
_ => InteractionResult::Unhandled, _ => InteractionResult::Unhandled,

View file

@ -26,7 +26,7 @@ pub static FPS: Lazy<RwLock<(f64, f64)>> = Lazy::new(|| RwLock::new((0.0, 0.0)))
pub struct UI { pub struct UI {
pub terminal: Arc<Mutex<Terminal<CrosstermBackend<Stdout>>>>, 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> { pub fn start_tui() -> Arc<UI> {
@ -111,18 +111,22 @@ impl UI {
let terminal = init(); let terminal = init();
Self { Self {
terminal: Arc::new(Mutex::new(terminal)), 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>) { 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) { pub async fn handle_input(self: Arc<Self>, key_event: KeyEvent) {
let result = { let result = {
let mut guard = self.screen.write().await; let mut stack = self.screen_stack.write().await;
if let Some(screen) = guard.as_mut() { if let Some(screen) = stack.last_mut() {
screen.handle_input(key_event) screen.handle_input(key_event)
} else { } else {
return; return;
@ -138,7 +142,12 @@ impl UI {
ui.set_screen(screen).await; ui.set_screen(screen).await;
} }
InteractionResult::CloseScreen => { 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::Handled => {}
InteractionResult::Unhandled => {} InteractionResult::Unhandled => {}
@ -146,7 +155,7 @@ impl UI {
} }
pub async fn render(&self) { 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(); let mut terminal = self.terminal.lock().unwrap();
terminal terminal
.draw(|f| { .draw(|f| {

View file

@ -20,6 +20,7 @@ mod util;
use crate::communities::community_manager; use crate::communities::community_manager;
use crate::communities::interactables::registry; use crate::communities::interactables::registry;
use crate::gui::app_state;
use crate::gui::app_state::AppState; use crate::gui::app_state::AppState;
use crate::gui::screens::main_screen::MainScreen; use crate::gui::screens::main_screen::MainScreen;
use crate::gui::ui::start_tui; use crate::gui::ui::start_tui;
@ -78,6 +79,7 @@ async fn main() {
println!("You can find this at 'agreements'!"); println!("You can find this at 'agreements'!");
return; return;
} }
app_state::setup();
let main_screen = MainScreen::new(ui.clone()).await; let main_screen = MainScreen::new(ui.clone()).await;
ui.set_screen(Box::new(main_screen)).await; ui.set_screen(Box::new(main_screen)).await;

View file

@ -59,7 +59,7 @@ async fn ensure_initial_consent(ui: Arc<UI>, state: &mut ConsentState) -> Result
} }
} }
&state.save_state(); let _ = &state.save_state();
Ok(()) Ok(())
} }
UserChoice::Deny => Err(()), UserChoice::Deny => Err(()),
@ -77,7 +77,6 @@ async fn ensure_updates(ui: Arc<UI>, state: &mut ConsentState) -> Result<(), ()>
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
ui.set_screen(Box::new(TermsUpdaterScreen::new( ui.set_screen(Box::new(TermsUpdaterScreen::new(
ui.clone(),
eula_update.clone(), eula_update.clone(),
tos_update.clone(), tos_update.clone(),
privacy_update.clone(), privacy_update.clone(),

View file

@ -2,5 +2,4 @@ pub mod buttons;
pub mod consent_state; pub mod consent_state;
pub mod doc; pub mod doc;
pub mod focus; pub mod focus;
pub mod md_viewer;
pub mod terms_getter; pub mod terms_getter;