add sending screen and keybinds
This commit is contained in:
parent
ce87f62317
commit
c8621da2f0
3 changed files with 110 additions and 40 deletions
|
@ -28,12 +28,18 @@ pub struct App {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum CurrentScreen {
|
pub enum CurrentScreen {
|
||||||
Main,
|
Main,
|
||||||
Sending,
|
Sending(SendingScreen),
|
||||||
Receiving,
|
Receiving,
|
||||||
Stopping,
|
Stopping,
|
||||||
Logging,
|
Logging,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum SendingScreen {
|
||||||
|
Files,
|
||||||
|
Peers,
|
||||||
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(service: JoecalService, event_listener: UnboundedReceiver<TransferEvent>) -> Self {
|
pub fn new(service: JoecalService, event_listener: UnboundedReceiver<TransferEvent>) -> Self {
|
||||||
App {
|
App {
|
||||||
|
@ -81,7 +87,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_key_event(&mut self, key_event: KeyEvent) {
|
pub fn handle_key_event(&mut self, key_event: KeyEvent) {
|
||||||
match self.screen.last().unwrap() {
|
match self.screen.last_mut().unwrap() {
|
||||||
CurrentScreen::Logging => match key_event.code {
|
CurrentScreen::Logging => match key_event.code {
|
||||||
KeyCode::Esc => self.pop(),
|
KeyCode::Esc => self.pop(),
|
||||||
KeyCode::Left => change_log_level(-1),
|
KeyCode::Left => change_log_level(-1),
|
||||||
|
@ -98,6 +104,22 @@ impl App {
|
||||||
KeyCode::Char('q') => self.exit(),
|
KeyCode::Char('q') => self.exit(),
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
CurrentScreen::Sending(s) => match s {
|
||||||
|
SendingScreen::Files => match key_event.code {
|
||||||
|
KeyCode::Esc => self.pop(),
|
||||||
|
KeyCode::Char('q') => self.exit(),
|
||||||
|
KeyCode::Tab => *s = SendingScreen::Peers,
|
||||||
|
KeyCode::Enter => todo!("send the selected file or enter directory"),
|
||||||
|
_ => todo!("have the file picker handle it"),
|
||||||
|
},
|
||||||
|
SendingScreen::Peers => match key_event.code {
|
||||||
|
KeyCode::Esc => self.pop(),
|
||||||
|
KeyCode::Char('q') => self.exit(),
|
||||||
|
KeyCode::Tab => *s = SendingScreen::Files,
|
||||||
|
KeyCode::Enter => todo!("send to the selected peer"),
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
},
|
||||||
_ => match key_event.code {
|
_ => match key_event.code {
|
||||||
KeyCode::Char('q') => self.exit(),
|
KeyCode::Char('q') => self.exit(),
|
||||||
KeyCode::Char('s') => self.send(),
|
KeyCode::Char('s') => self.send(),
|
||||||
|
@ -157,8 +179,10 @@ impl App {
|
||||||
pub fn send(&mut self) {
|
pub fn send(&mut self) {
|
||||||
let last = self.screen.last();
|
let last = self.screen.last();
|
||||||
match last {
|
match last {
|
||||||
Some(CurrentScreen::Sending) => {}
|
Some(CurrentScreen::Sending(_)) => {}
|
||||||
_ => self.screen.push(CurrentScreen::Sending),
|
_ => self
|
||||||
|
.screen
|
||||||
|
.push(CurrentScreen::Sending(SendingScreen::Files)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ use ratatui::{
|
||||||
};
|
};
|
||||||
use tui_logger::{TuiLoggerLevelOutput, TuiLoggerWidget, TuiWidgetState};
|
use tui_logger::{TuiLoggerLevelOutput, TuiLoggerWidget, TuiWidgetState};
|
||||||
|
|
||||||
use super::{App, CurrentScreen, Peers};
|
use super::{App, CurrentScreen, Peers, SendingScreen};
|
||||||
|
|
||||||
static MAIN_MENU: LazyLock<Line> = LazyLock::new(|| {
|
static MAIN_MENU: LazyLock<Line> = LazyLock::new(|| {
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
|
@ -42,7 +42,7 @@ static LOGGING_MENU: LazyLock<Line> = LazyLock::new(|| {
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
|
|
||||||
static UPLOADS_MENU: LazyLock<Line> = LazyLock::new(|| {
|
static CONTENT_RECEIVE_MENU: LazyLock<Line> = LazyLock::new(|| {
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
" Select Previous ".into(),
|
" Select Previous ".into(),
|
||||||
"<UP>".blue().bold(),
|
"<UP>".blue().bold(),
|
||||||
|
@ -59,11 +59,48 @@ static UPLOADS_MENU: LazyLock<Line> = LazyLock::new(|| {
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static CONTENT_SEND_FILE_MENU: LazyLock<Line> = LazyLock::new(|| {
|
||||||
|
Line::from(vec![
|
||||||
|
" Select Previous ".into(),
|
||||||
|
"<UP>".blue().bold(),
|
||||||
|
" Select Next ".into(),
|
||||||
|
"<DOWN>".blue().bold(),
|
||||||
|
" Select ".into(),
|
||||||
|
"<ENTER>".blue().bold(),
|
||||||
|
" Parent Dir ".into(),
|
||||||
|
"<LEFT>".blue().bold(),
|
||||||
|
" Child Dir ".into(),
|
||||||
|
"<RIGHT>".blue().bold(),
|
||||||
|
" Peers ".into(),
|
||||||
|
"<TAB>".blue().bold(),
|
||||||
|
" Previous Screen ".into(),
|
||||||
|
"<ESC>".blue().bold(),
|
||||||
|
" Quit ".into(),
|
||||||
|
"<Q>".blue().bold(),
|
||||||
|
])
|
||||||
|
});
|
||||||
|
|
||||||
|
static CONTENT_SEND_PEERS_MENU: LazyLock<Line> = LazyLock::new(|| {
|
||||||
|
Line::from(vec![
|
||||||
|
" Select Previous ".into(),
|
||||||
|
"<UP>".blue().bold(),
|
||||||
|
" Select Next ".into(),
|
||||||
|
"<DOWN>".blue().bold(),
|
||||||
|
" Select ".into(),
|
||||||
|
"<ENTER>".blue().bold(),
|
||||||
|
" Files ".into(),
|
||||||
|
"<TAB>".blue().bold(),
|
||||||
|
" Previous Screen ".into(),
|
||||||
|
"<ESC>".blue().bold(),
|
||||||
|
" Quit ".into(),
|
||||||
|
"<Q>".blue().bold(),
|
||||||
|
])
|
||||||
|
});
|
||||||
|
|
||||||
impl Widget for &mut App {
|
impl Widget for &mut App {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
let main_layout =
|
let main_layout = Layout::vertical([Constraint::Min(5), Constraint::Min(3)]);
|
||||||
Layout::vertical([Constraint::Min(5), Constraint::Min(10), Constraint::Min(3)]);
|
let [top, bottom] = main_layout.areas(area);
|
||||||
let [top, _middle, bottom] = main_layout.areas(area);
|
|
||||||
|
|
||||||
let footer_layout =
|
let footer_layout =
|
||||||
Layout::horizontal([Constraint::Percentage(30), Constraint::Percentage(70)]);
|
Layout::horizontal([Constraint::Percentage(30), Constraint::Percentage(70)]);
|
||||||
|
@ -77,42 +114,68 @@ impl Widget for &mut App {
|
||||||
|
|
||||||
let subscreen_margin = Margin::new(2, 4);
|
let subscreen_margin = Margin::new(2, 4);
|
||||||
|
|
||||||
let mode = self.screen.last().unwrap();
|
let current_screen = self.screen.last().unwrap();
|
||||||
let ups: Vec<_> = self.receive_requests.values().collect();
|
|
||||||
match mode {
|
match current_screen {
|
||||||
CurrentScreen::Main => {
|
CurrentScreen::Main => {
|
||||||
main_page(*mode, &MAIN_MENU, area, buf);
|
let rx_reqs: Vec<_> = self.receive_requests.values().collect();
|
||||||
|
outer_frame(*current_screen, &MAIN_MENU, area, buf);
|
||||||
logger(header_right.inner(header_margin), buf);
|
logger(header_right.inner(header_margin), buf);
|
||||||
let peers = PeersWidget { peers: &self.peers };
|
let peers = PeersWidget { peers: &self.peers };
|
||||||
peers.render(footer_right.inner(footer_margin), buf);
|
peers.render(footer_right.inner(footer_margin), buf);
|
||||||
NetworkInfoWidget.render(footer_left.inner(footer_margin), buf);
|
NetworkInfoWidget.render(footer_left.inner(footer_margin), buf);
|
||||||
upload_requests(
|
receive_requests(
|
||||||
&ups,
|
&rx_reqs,
|
||||||
&mut self.upload_state,
|
&mut self.upload_state,
|
||||||
header_left.inner(header_margin),
|
header_left.inner(header_margin),
|
||||||
buf,
|
buf,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
CurrentScreen::Logging => {
|
CurrentScreen::Logging => {
|
||||||
main_page(*mode, &LOGGING_MENU, area, buf);
|
outer_frame(*current_screen, &LOGGING_MENU, area, buf);
|
||||||
logger(area.inner(subscreen_margin), buf);
|
logger(area.inner(subscreen_margin), buf);
|
||||||
}
|
}
|
||||||
CurrentScreen::Receiving => {
|
CurrentScreen::Receiving => {
|
||||||
main_page(*mode, &UPLOADS_MENU, area, buf);
|
let rx_reqs: Vec<_> = self.receive_requests.values().collect();
|
||||||
upload_requests(
|
outer_frame(*current_screen, &CONTENT_RECEIVE_MENU, area, buf);
|
||||||
&ups,
|
receive_requests(
|
||||||
|
&rx_reqs,
|
||||||
&mut self.upload_state,
|
&mut self.upload_state,
|
||||||
area.inner(subscreen_margin),
|
area.inner(subscreen_margin),
|
||||||
buf,
|
buf,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
CurrentScreen::Sending(s) => match s {
|
||||||
|
SendingScreen::Files => {
|
||||||
|
outer_frame(*current_screen, &CONTENT_SEND_FILE_MENU, area, buf)
|
||||||
|
}
|
||||||
|
SendingScreen::Peers => {
|
||||||
|
outer_frame(*current_screen, &CONTENT_SEND_PEERS_MENU, area, buf)
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
main_page(*mode, &MAIN_MENU, area, buf);
|
outer_frame(*current_screen, &MAIN_MENU, area, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn outer_frame(screen: CurrentScreen, menu: &Line, area: Rect, buf: &mut Buffer) {
|
||||||
|
let title = Line::from(" Joecalsend ".bold());
|
||||||
|
let block = Block::bordered()
|
||||||
|
.title(title.centered())
|
||||||
|
.title_bottom(menu.clone().centered())
|
||||||
|
.border_set(border::THICK);
|
||||||
|
|
||||||
|
let current_screen = format!("{screen:?}",);
|
||||||
|
let text = Text::from(Line::from(current_screen.yellow()));
|
||||||
|
|
||||||
|
Paragraph::new(text)
|
||||||
|
.centered()
|
||||||
|
.block(block)
|
||||||
|
.render(area, buf);
|
||||||
|
}
|
||||||
|
|
||||||
fn logger(area: Rect, buf: &mut Buffer) {
|
fn logger(area: Rect, buf: &mut Buffer) {
|
||||||
let title = Line::from(log::max_level().as_str());
|
let title = Line::from(log::max_level().as_str());
|
||||||
let logger = TuiLoggerWidget::default()
|
let logger = TuiLoggerWidget::default()
|
||||||
|
@ -128,23 +191,7 @@ fn logger(area: Rect, buf: &mut Buffer) {
|
||||||
logger.render(area, buf);
|
logger.render(area, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_page(screen: CurrentScreen, menu: &Line, area: Rect, buf: &mut Buffer) {
|
fn receive_requests(
|
||||||
let title = Line::from(" Joecalsend ".bold());
|
|
||||||
let block = Block::bordered()
|
|
||||||
.title(title.centered())
|
|
||||||
.title_bottom(menu.clone().centered())
|
|
||||||
.border_set(border::THICK);
|
|
||||||
|
|
||||||
let current_screen = format!("{screen:?}",);
|
|
||||||
let text = Text::from(Line::from(current_screen.yellow()));
|
|
||||||
|
|
||||||
Paragraph::new(text)
|
|
||||||
.centered()
|
|
||||||
.block(block)
|
|
||||||
.render(area, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn upload_requests(
|
|
||||||
requests: &[&ReceiveRequest],
|
requests: &[&ReceiveRequest],
|
||||||
state: &mut TableState,
|
state: &mut TableState,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
|
|
|
@ -215,10 +215,9 @@ pub async fn register_prepare_upload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let confirmation = rx.recv().await;
|
let Some(confirmation) = rx.recv().await else {
|
||||||
|
|
||||||
let Some(confirmation) = confirmation else {
|
|
||||||
// the frontend must have dropped the tx before trying to send a reply back
|
// the frontend must have dropped the tx before trying to send a reply back
|
||||||
|
warn!("could not read content receive response from the frontend");
|
||||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue