[WIP] Console Box for Main UI
This commit is contained in:
parent
9416a9744f
commit
b8658e84b9
9 changed files with 409 additions and 19 deletions
147
src/gui/elements/console_card.rs
Normal file
147
src/gui/elements/console_card.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
use actix_web::web::block;
|
||||||
|
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||||
|
use ratatui::{
|
||||||
|
Frame,
|
||||||
|
layout::{Alignment, Constraint, Layout, Rect},
|
||||||
|
style::{Color, Style},
|
||||||
|
text::{Line, Span},
|
||||||
|
widgets::{Block, Borders, Paragraph},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::gui::{
|
||||||
|
elements::elements::{Element, InteractableElement, JoinableElement},
|
||||||
|
interaction_result::InteractionResult,
|
||||||
|
util::borders::draw_block_joins,
|
||||||
|
};
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
pub struct ConsoleCard {
|
||||||
|
focused: bool,
|
||||||
|
pub title: String,
|
||||||
|
pub content: String,
|
||||||
|
|
||||||
|
borders: Borders,
|
||||||
|
joins: Borders,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConsoleCard {
|
||||||
|
pub fn new(title: &str, content: &str) -> Self {
|
||||||
|
ConsoleCard {
|
||||||
|
focused: false,
|
||||||
|
title: title.to_string(),
|
||||||
|
content: content.to_string(),
|
||||||
|
borders: Borders::ALL,
|
||||||
|
joins: Borders::NONE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element for ConsoleCard {
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&self, f: &mut Frame, r: Rect) {
|
||||||
|
let block = Block::default()
|
||||||
|
.borders(self.borders)
|
||||||
|
.title(self.title.clone())
|
||||||
|
.title_style(Style::default().fg(Color::White))
|
||||||
|
.border_style(if self.focused {
|
||||||
|
Style::default().fg(Color::Yellow)
|
||||||
|
} else {
|
||||||
|
Style::default()
|
||||||
|
})
|
||||||
|
.style(if self.focused {
|
||||||
|
Style::default().fg(Color::White)
|
||||||
|
} else {
|
||||||
|
Style::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let par = Paragraph::new(Line::from(Span::from(self.content.clone())))
|
||||||
|
.block(block)
|
||||||
|
.scroll((0, 0));
|
||||||
|
f.render_widget(par, r);
|
||||||
|
draw_block_joins(f, r, self.borders, self.joins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JoinableElement for ConsoleCard {
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element(&self) -> &dyn Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element_mut(&mut self) -> &mut dyn Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_borders(&mut self, borders: Borders) {
|
||||||
|
self.borders = borders;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_joins(&mut self, joins: Borders) {
|
||||||
|
self.joins = joins;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractableElement for ConsoleCard {
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element(&self) -> &dyn Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element_mut(&mut self) -> &mut dyn Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interact(&mut self, key: KeyEvent) -> InteractionResult {
|
||||||
|
match key.code {
|
||||||
|
KeyCode::Enter => {
|
||||||
|
self.content = "".to_string();
|
||||||
|
InteractionResult::Handled
|
||||||
|
}
|
||||||
|
KeyCode::Backspace => {
|
||||||
|
self.content.pop();
|
||||||
|
InteractionResult::Handled
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if let Some(c) = key.code.as_char() {
|
||||||
|
self.content.push(c);
|
||||||
|
InteractionResult::Handled
|
||||||
|
} else {
|
||||||
|
InteractionResult::Unhandled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_focus(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_focused(&self) -> bool {
|
||||||
|
self.focused
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focus(&mut self, f: bool) {
|
||||||
|
self.focused = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
use ratatui::{Frame, layout::Rect};
|
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};
|
||||||
|
|
||||||
|
|
@ -11,6 +11,15 @@ pub trait Element: Send + Sync + Any {
|
||||||
|
|
||||||
fn render(&self, f: &mut Frame, r: Rect);
|
fn render(&self, f: &mut Frame, r: Rect);
|
||||||
}
|
}
|
||||||
|
pub trait JoinableElement: Send + Sync + Any {
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||||
|
fn as_element(&self) -> &dyn Element;
|
||||||
|
fn as_element_mut(&mut self) -> &mut dyn Element;
|
||||||
|
|
||||||
|
fn set_borders(&mut self, borders: Borders);
|
||||||
|
fn set_joins(&mut self, joins: Borders);
|
||||||
|
}
|
||||||
|
|
||||||
pub trait InfoElement: Send + Sync + Any {
|
pub trait InfoElement: Send + Sync + Any {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::gui::elements::elements::InteractableElement;
|
use crate::gui::elements::elements::{InteractableElement, JoinableElement};
|
||||||
use crate::gui::interaction_result::InteractionResult;
|
use crate::gui::interaction_result::InteractionResult;
|
||||||
|
use crate::gui::util::borders::draw_block_joins;
|
||||||
use crate::{APP_STATE, gui::elements::elements::Element};
|
use crate::{APP_STATE, gui::elements::elements::Element};
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
|
|
@ -20,6 +21,9 @@ pub struct UiLogEntry {
|
||||||
pub struct LogCard {
|
pub struct LogCard {
|
||||||
focused: bool,
|
focused: bool,
|
||||||
scroll: u16,
|
scroll: u16,
|
||||||
|
|
||||||
|
pub borders: Borders,
|
||||||
|
pub joins: Borders,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogCard {
|
impl LogCard {
|
||||||
|
|
@ -27,6 +31,8 @@ impl LogCard {
|
||||||
Self {
|
Self {
|
||||||
focused: false,
|
focused: false,
|
||||||
scroll: 0,
|
scroll: 0,
|
||||||
|
borders: Borders::ALL,
|
||||||
|
joins: Borders::NONE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -49,8 +55,12 @@ impl Element for LogCard {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let block = Block::default()
|
let block = Block::default()
|
||||||
.title("Logs")
|
.title(if self.focused {
|
||||||
.borders(Borders::ALL)
|
"Logs J/K to scroll"
|
||||||
|
} else {
|
||||||
|
"Logs"
|
||||||
|
})
|
||||||
|
.borders(self.borders)
|
||||||
.border_style(if self.focused {
|
.border_style(if self.focused {
|
||||||
Style::default().fg(Color::Yellow)
|
Style::default().fg(Color::Yellow)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -63,6 +73,32 @@ impl Element for LogCard {
|
||||||
.scroll((self.scroll, 0));
|
.scroll((self.scroll, 0));
|
||||||
|
|
||||||
f.render_widget(paragraph, area);
|
f.render_widget(paragraph, area);
|
||||||
|
draw_block_joins(f, area, self.borders, self.joins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl JoinableElement for LogCard {
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element(&self) -> &dyn Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_element_mut(&mut self) -> &mut dyn Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_borders(&mut self, borders: Borders) {
|
||||||
|
self.borders = borders;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_joins(&mut self, joins: Borders) {
|
||||||
|
self.joins = joins;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl InteractableElement for LogCard {
|
impl InteractableElement for LogCard {
|
||||||
|
|
@ -84,13 +120,13 @@ impl InteractableElement for LogCard {
|
||||||
|
|
||||||
fn interact(&mut self, key: KeyEvent) -> InteractionResult {
|
fn interact(&mut self, key: KeyEvent) -> InteractionResult {
|
||||||
match key.code {
|
match key.code {
|
||||||
KeyCode::Up => {
|
KeyCode::Char('J') | KeyCode::Char('j') => {
|
||||||
if self.scroll > 0 {
|
if self.scroll > 0 {
|
||||||
self.scroll -= 1;
|
self.scroll -= 1;
|
||||||
}
|
}
|
||||||
InteractionResult::Handled
|
InteractionResult::Handled
|
||||||
}
|
}
|
||||||
KeyCode::Down => {
|
KeyCode::Char('K') | KeyCode::Char('k') => {
|
||||||
self.scroll += 1;
|
self.scroll += 1;
|
||||||
InteractionResult::Handled
|
InteractionResult::Handled
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,3 +28,22 @@ impl Debug for InteractionResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for InteractionResult {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
InteractionResult::OpenScreen { screen: _ },
|
||||||
|
InteractionResult::OpenScreen { screen: _ },
|
||||||
|
) => true,
|
||||||
|
(
|
||||||
|
InteractionResult::OpenFutureScreen { screen: _ },
|
||||||
|
InteractionResult::OpenFutureScreen { screen: _ },
|
||||||
|
) => true,
|
||||||
|
(InteractionResult::CloseScreen, InteractionResult::CloseScreen) => true,
|
||||||
|
(InteractionResult::Handled, InteractionResult::Handled) => true,
|
||||||
|
(InteractionResult::Unhandled, InteractionResult::Unhandled) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod elements {
|
pub mod elements {
|
||||||
|
pub mod console_card;
|
||||||
pub mod elements;
|
pub mod elements;
|
||||||
pub mod log_card;
|
pub mod log_card;
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +9,9 @@ pub mod screens {
|
||||||
pub mod terms_checker;
|
pub mod terms_checker;
|
||||||
pub mod terms_updater;
|
pub mod terms_updater;
|
||||||
}
|
}
|
||||||
|
pub mod util {
|
||||||
|
pub mod borders;
|
||||||
|
}
|
||||||
pub mod app_state;
|
pub mod app_state;
|
||||||
pub mod input_handler;
|
pub mod input_handler;
|
||||||
pub mod interaction_result;
|
pub mod interaction_result;
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,125 @@
|
||||||
use crate::gui::{
|
use crate::gui::{
|
||||||
elements::{
|
elements::{
|
||||||
elements::{Element, InteractableElement},
|
console_card::ConsoleCard,
|
||||||
|
elements::{Element, InteractableElement, JoinableElement},
|
||||||
log_card::LogCard,
|
log_card::LogCard,
|
||||||
},
|
},
|
||||||
interaction_result::InteractionResult,
|
interaction_result::InteractionResult,
|
||||||
screens::screens::Screen,
|
screens::screens::{NavDirection, Screen},
|
||||||
ui::UI,
|
ui::UI,
|
||||||
};
|
};
|
||||||
use crossterm::event::KeyEvent;
|
|
||||||
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
Frame,
|
Frame,
|
||||||
layout::{Constraint, Layout, Margin, Rect},
|
layout::{Constraint, Layout, Margin, Rect},
|
||||||
widgets::{Block, Borders},
|
widgets::{Block, Borders},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{any::Any, sync::Arc};
|
use std::{any::Any, sync::Arc};
|
||||||
|
|
||||||
pub struct MainScreen {
|
pub struct MainScreen {
|
||||||
ui: Arc<UI>,
|
ui: Arc<UI>,
|
||||||
log_card: LogCard,
|
elements: Vec<Box<dyn InteractableElement>>,
|
||||||
|
nav_grid: Vec<Vec<Option<usize>>>,
|
||||||
|
selected_coords: (usize, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainScreen {
|
impl MainScreen {
|
||||||
pub async fn new(ui: Arc<UI>) -> Self {
|
pub async fn new(ui: Arc<UI>) -> Self {
|
||||||
|
let mut elements: Vec<Box<dyn InteractableElement>> = Vec::new();
|
||||||
|
let mut nav_grid: Vec<Vec<Option<usize>>> = Vec::new();
|
||||||
|
|
||||||
let mut log_card = LogCard::new();
|
let mut log_card = LogCard::new();
|
||||||
log_card.focus(true);
|
log_card.set_borders(Borders::TOP.union(Borders::RIGHT).union(Borders::LEFT));
|
||||||
MainScreen { ui, log_card }
|
let mut console_card = ConsoleCard::new("Console", "");
|
||||||
|
console_card.set_joins(Borders::TOP);
|
||||||
|
elements.push(Box::new(log_card));
|
||||||
|
elements.push(Box::new(console_card));
|
||||||
|
|
||||||
|
nav_grid.push(vec![Some(0)]);
|
||||||
|
nav_grid.push(vec![Some(1)]);
|
||||||
|
|
||||||
|
let mut screen = MainScreen {
|
||||||
|
ui,
|
||||||
|
elements,
|
||||||
|
nav_grid,
|
||||||
|
selected_coords: (1, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
screen.focus_current();
|
||||||
|
screen
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focus_current(&mut self) {
|
||||||
|
let (y, x) = self.selected_coords;
|
||||||
|
if let Some(Some(index)) = self.nav_grid.get(y).and_then(|row| row.get(x)) {
|
||||||
|
if let Some(element) = self.elements.get_mut(*index) {
|
||||||
|
if element.can_focus() {
|
||||||
|
element.focus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unfocus_current(&mut self, y: usize, x: usize) {
|
||||||
|
if let Some(Some(index)) = self.nav_grid.get(y).and_then(|row| row.get(x)) {
|
||||||
|
if let Some(element) = self.elements.get_mut(*index) {
|
||||||
|
element.focus(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn navigate(&mut self, direction: NavDirection) {
|
||||||
|
let (mut y, mut x) = self.selected_coords;
|
||||||
|
|
||||||
|
self.unfocus_current(y, x);
|
||||||
|
|
||||||
|
match direction {
|
||||||
|
NavDirection::Up => {
|
||||||
|
if y > 0 {
|
||||||
|
y -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NavDirection::Down => {
|
||||||
|
if y < self.nav_grid.len() - 1 {
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NavDirection::Left => {
|
||||||
|
if x > 0 {
|
||||||
|
x -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NavDirection::Right => {
|
||||||
|
if let Some(row) = self.nav_grid.get(y) {
|
||||||
|
if x < row.len() - 1 {
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp X to row length
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Screen for MainScreen {
|
impl Screen for MainScreen {
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
|
|
@ -42,7 +135,6 @@ impl Screen for MainScreen {
|
||||||
|
|
||||||
fn render(&self, f: &mut Frame, rect: Rect) {
|
fn render(&self, f: &mut Frame, rect: Rect) {
|
||||||
let main_block = Block::default().title("Main").borders(Borders::ALL);
|
let main_block = Block::default().title("Main").borders(Borders::ALL);
|
||||||
|
|
||||||
f.render_widget(main_block, rect);
|
f.render_widget(main_block, rect);
|
||||||
|
|
||||||
let inner = rect.inner(Margin {
|
let inner = rect.inner(Margin {
|
||||||
|
|
@ -50,16 +142,33 @@ impl Screen for MainScreen {
|
||||||
horizontal: 1,
|
horizontal: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
let chunks = Layout::vertical([Constraint::Min(0)]).split(inner);
|
let chunks = Layout::vertical([Constraint::Min(0), Constraint::Length(3)]).split(inner);
|
||||||
|
|
||||||
self.log_card.render(f, 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, chunks[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(Some(index)) = self.nav_grid.get(1).and_then(|r| r.get(0)) {
|
||||||
|
self.elements[*index].as_element().render(f, chunks[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_input(&mut self, event: KeyEvent) -> InteractionResult {
|
fn handle_input(&mut self, event: KeyEvent) -> InteractionResult {
|
||||||
if self.log_card.is_focused() {
|
match event.code {
|
||||||
return self.log_card.interact(event);
|
KeyCode::Up => self.navigate(NavDirection::Up),
|
||||||
|
KeyCode::Down => self.navigate(NavDirection::Down),
|
||||||
|
KeyCode::Left => self.navigate(NavDirection::Left),
|
||||||
|
KeyCode::Right => self.navigate(NavDirection::Right),
|
||||||
|
_ => {
|
||||||
|
let (y, x) = self.selected_coords;
|
||||||
|
if let Some(Some(index)) = self.nav_grid.get(y).and_then(|r| r.get(x)) {
|
||||||
|
if let Some(el) = self.elements.get_mut(*index) {
|
||||||
|
return el.interact(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionResult::Unhandled
|
InteractionResult::Handled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
63
src/gui/util/borders.rs
Normal file
63
src/gui/util/borders.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
use ratatui::layout::Rect;
|
||||||
|
use ratatui::prelude::*;
|
||||||
|
use ratatui::style::Style;
|
||||||
|
use ratatui::widgets::Borders;
|
||||||
|
|
||||||
|
fn set_join_char(frame: &mut Frame, x: u16, y: u16, c: char) {
|
||||||
|
frame
|
||||||
|
.buffer_mut()
|
||||||
|
.set_string(x, y, c.to_string(), Style::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_block_joins(frame: &mut Frame, area: Rect, borders: Borders, joins: Borders) {
|
||||||
|
let x0 = area.x;
|
||||||
|
let y0 = area.y;
|
||||||
|
let x1 = area.x + area.width - 1;
|
||||||
|
let y1 = area.y + area.height - 1;
|
||||||
|
|
||||||
|
if borders.contains(Borders::TOP) && borders.contains(Borders::LEFT) {
|
||||||
|
let top_left = match (joins.contains(Borders::TOP), joins.contains(Borders::LEFT)) {
|
||||||
|
(true, true) => '┼',
|
||||||
|
(true, false) => '├',
|
||||||
|
(false, true) => '┬',
|
||||||
|
(false, false) => '┌',
|
||||||
|
};
|
||||||
|
set_join_char(frame, x0, y0, top_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if borders.contains(Borders::TOP) && borders.contains(Borders::RIGHT) {
|
||||||
|
let top_right = match (joins.contains(Borders::TOP), joins.contains(Borders::RIGHT)) {
|
||||||
|
(true, true) => '┼',
|
||||||
|
(true, false) => '┤',
|
||||||
|
(false, true) => '┬',
|
||||||
|
(false, false) => '┐',
|
||||||
|
};
|
||||||
|
set_join_char(frame, x1, y0, top_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
if borders.contains(Borders::BOTTOM) && borders.contains(Borders::LEFT) {
|
||||||
|
let bottom_left = match (
|
||||||
|
joins.contains(Borders::BOTTOM),
|
||||||
|
joins.contains(Borders::LEFT),
|
||||||
|
) {
|
||||||
|
(true, true) => '┼',
|
||||||
|
(true, false) => '├',
|
||||||
|
(false, true) => '┴',
|
||||||
|
(false, false) => '└',
|
||||||
|
};
|
||||||
|
set_join_char(frame, x0, y1, bottom_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if borders.contains(Borders::BOTTOM) && borders.contains(Borders::RIGHT) {
|
||||||
|
let bottom_right = match (
|
||||||
|
joins.contains(Borders::BOTTOM),
|
||||||
|
joins.contains(Borders::RIGHT),
|
||||||
|
) {
|
||||||
|
(true, true) => '┼',
|
||||||
|
(true, false) => '┤',
|
||||||
|
(false, true) => '┴',
|
||||||
|
(false, false) => '┘',
|
||||||
|
};
|
||||||
|
set_join_char(frame, x1, y1, bottom_right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ async fn main() {
|
||||||
if ACTIVE_TASKS.lock().unwrap().is_empty() {
|
if ACTIVE_TASKS.lock().unwrap().is_empty() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sleep(Duration::from_secs(1)).await;
|
sleep(Duration::from_millis(100)).await;
|
||||||
}
|
}
|
||||||
println!(
|
println!(
|
||||||
"Please accept our Privacy Policy & Terms of Serivce before using Tensamin Services!"
|
"Please accept our Privacy Policy & Terms of Serivce before using Tensamin Services!"
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,9 @@ impl OmikronConnection {
|
||||||
let sel_arc_clone = self.clone();
|
let sel_arc_clone = self.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
|
if *SHUTDOWN.read().await {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if !sel_arc_clone.is_connected().await {
|
if !sel_arc_clone.is_connected().await {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue