feature (ui): added a cli panel to contoll the UI similar to what you have when hitting colon in vim

This commit is contained in:
antifallobst 2023-07-10 00:10:51 +02:00
parent 8d6e7c976e
commit 200b9143b3
Signed by: antifallobst
GPG Key ID: 2B4F402172791BAF
3 changed files with 99 additions and 5 deletions

View File

@ -132,6 +132,13 @@ impl Event {
}) => { }) => {
app.ui.cycle_main_input_position_rev(); app.ui.cycle_main_input_position_rev();
} }
crossterm::event::Event::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
..
}) => {
app.ui.cli_enable();
}
input => match app.ui.input_position() { input => match app.ui.input_position() {
ui::MainInputPosition::MessageCompose => { ui::MainInputPosition::MessageCompose => {
match input { match input {
@ -239,6 +246,23 @@ impl Event {
_ => (), _ => (),
}; };
} }
ui::MainInputPosition::CLI => {
if let Some(cli) = &mut app.ui.cli {
match input {
crossterm::event::Event::Key(KeyEvent {
code: KeyCode::Enter,
..
}) => {
let cli_event = cli.lines()[0].clone();
app.status.cli_event(cli_event);
app.ui.cli_disable();
}
_ => {
cli.input(tui_textarea::Input::from(input));
}
};
};
}
_ => (), _ => (),
}, },
}; };

View File

@ -206,4 +206,8 @@ impl Status {
pub fn set_state(&mut self, state: State) { pub fn set_state(&mut self, state: State) {
self.state = state; self.state = state;
} }
pub fn cli_event(&mut self, event: String) {
info!("CLI Event: {}", event);
}
} }

View File

@ -32,13 +32,14 @@ pub enum SetupInputPosition {
Ok, Ok,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq)]
pub enum MainInputPosition { pub enum MainInputPosition {
Status, Status,
Rooms, Rooms,
Messages, Messages,
MessageCompose, MessageCompose,
RoomInfo, RoomInfo,
CLI,
} }
pub struct SetupUI<'a> { pub struct SetupUI<'a> {
@ -55,6 +56,7 @@ pub struct UI<'a> {
input_position: MainInputPosition, input_position: MainInputPosition,
pub rooms_state: ListState, pub rooms_state: ListState,
pub message_compose: TextArea<'a>, pub message_compose: TextArea<'a>,
pub cli: Option<TextArea<'a>>,
pub setup_ui: Option<SetupUI<'a>>, pub setup_ui: Option<SetupUI<'a>>,
} }
@ -266,6 +268,7 @@ impl UI<'_> {
input_position: MainInputPosition::Rooms, input_position: MainInputPosition::Rooms,
rooms_state: ListState::default(), rooms_state: ListState::default(),
message_compose, message_compose,
cli: None,
setup_ui: None, setup_ui: None,
} }
} }
@ -276,17 +279,25 @@ impl UI<'_> {
MainInputPosition::Rooms => MainInputPosition::Messages, MainInputPosition::Rooms => MainInputPosition::Messages,
MainInputPosition::Messages => MainInputPosition::MessageCompose, MainInputPosition::Messages => MainInputPosition::MessageCompose,
MainInputPosition::MessageCompose => MainInputPosition::RoomInfo, MainInputPosition::MessageCompose => MainInputPosition::RoomInfo,
MainInputPosition::RoomInfo => MainInputPosition::Status, MainInputPosition::RoomInfo => match self.cli {
Some(_) => MainInputPosition::CLI,
None => MainInputPosition::Status,
},
MainInputPosition::CLI => MainInputPosition::Status,
}; };
} }
pub fn cycle_main_input_position_rev(&mut self) { pub fn cycle_main_input_position_rev(&mut self) {
self.input_position = match self.input_position { self.input_position = match self.input_position {
MainInputPosition::Status => MainInputPosition::RoomInfo, MainInputPosition::Status => match self.cli {
Some(_) => MainInputPosition::CLI,
None => MainInputPosition::RoomInfo,
},
MainInputPosition::Rooms => MainInputPosition::Status, MainInputPosition::Rooms => MainInputPosition::Status,
MainInputPosition::Messages => MainInputPosition::Rooms, MainInputPosition::Messages => MainInputPosition::Rooms,
MainInputPosition::MessageCompose => MainInputPosition::Messages, MainInputPosition::MessageCompose => MainInputPosition::Messages,
MainInputPosition::RoomInfo => MainInputPosition::MessageCompose, MainInputPosition::RoomInfo => MainInputPosition::MessageCompose,
MainInputPosition::CLI => MainInputPosition::RoomInfo,
}; };
} }
@ -303,8 +314,31 @@ impl UI<'_> {
); );
} }
pub fn cli_enable(&mut self) {
self.input_position = MainInputPosition::CLI;
if self.cli.is_some() {
return;
}
let mut cli = TextArea::default();
cli.set_block(Block::default().borders(Borders::ALL));
self.cli = Some(cli);
}
pub fn cli_disable(&mut self) {
if self.input_position == MainInputPosition::CLI {
self.cycle_main_input_position();
}
self.cli = None;
}
pub async fn update(&mut self, status: &Status) -> Result<()> { pub async fn update(&mut self, status: &Status) -> Result<()> {
let chunk = self.terminal.size()?; let chunks = match self.cli {
Some(_) => Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(10), Constraint::Length(3)].as_ref())
.split(self.terminal.size()?),
None => vec![self.terminal.size()?],
};
let main_chunks = Layout::default() let main_chunks = Layout::default()
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
@ -316,7 +350,7 @@ impl UI<'_> {
] ]
.as_ref(), .as_ref(),
) )
.split(chunk); .split(chunks[0]);
let left_chunks = Layout::default() let left_chunks = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
@ -450,6 +484,9 @@ impl UI<'_> {
let colors = match self.input_position { let colors = match self.input_position {
MainInputPosition::Status => { MainInputPosition::Status => {
textarea_inactivate(&mut self.message_compose); textarea_inactivate(&mut self.message_compose);
if let Some(cli) = &mut self.cli {
textarea_inactivate(cli);
}
vec![ vec![
Color::White, Color::White,
Color::DarkGray, Color::DarkGray,
@ -460,6 +497,9 @@ impl UI<'_> {
} }
MainInputPosition::Rooms => { MainInputPosition::Rooms => {
textarea_inactivate(&mut self.message_compose); textarea_inactivate(&mut self.message_compose);
if let Some(cli) = &mut self.cli {
textarea_inactivate(cli);
}
vec![ vec![
Color::DarkGray, Color::DarkGray,
Color::White, Color::White,
@ -470,6 +510,9 @@ impl UI<'_> {
} }
MainInputPosition::Messages => { MainInputPosition::Messages => {
textarea_inactivate(&mut self.message_compose); textarea_inactivate(&mut self.message_compose);
if let Some(cli) = &mut self.cli {
textarea_inactivate(cli);
}
vec![ vec![
Color::DarkGray, Color::DarkGray,
Color::DarkGray, Color::DarkGray,
@ -480,6 +523,9 @@ impl UI<'_> {
} }
MainInputPosition::MessageCompose => { MainInputPosition::MessageCompose => {
textarea_activate(&mut self.message_compose); textarea_activate(&mut self.message_compose);
if let Some(cli) = &mut self.cli {
textarea_inactivate(cli);
}
vec![ vec![
Color::DarkGray, Color::DarkGray,
Color::DarkGray, Color::DarkGray,
@ -490,6 +536,9 @@ impl UI<'_> {
} }
MainInputPosition::RoomInfo => { MainInputPosition::RoomInfo => {
textarea_inactivate(&mut self.message_compose); textarea_inactivate(&mut self.message_compose);
if let Some(cli) = &mut self.cli {
textarea_inactivate(cli);
}
vec![ vec![
Color::DarkGray, Color::DarkGray,
Color::DarkGray, Color::DarkGray,
@ -498,6 +547,19 @@ impl UI<'_> {
Color::White, Color::White,
] ]
} }
MainInputPosition::CLI => {
textarea_inactivate(&mut self.message_compose);
if let Some(cli) = &mut self.cli {
textarea_activate(cli);
}
vec![
Color::DarkGray,
Color::DarkGray,
Color::DarkGray,
Color::DarkGray,
Color::DarkGray,
]
}
}; };
// initiate the widgets // initiate the widgets
@ -555,6 +617,10 @@ impl UI<'_> {
frame.render_stateful_widget(rooms_panel, left_chunks[1], &mut self.rooms_state); frame.render_stateful_widget(rooms_panel, left_chunks[1], &mut self.rooms_state);
frame.render_stateful_widget(messages_panel, middle_chunks[0], &mut messages_state); frame.render_stateful_widget(messages_panel, middle_chunks[0], &mut messages_state);
frame.render_widget(self.message_compose.widget(), middle_chunks[1]); frame.render_widget(self.message_compose.widget(), middle_chunks[1]);
match &self.cli {
Some(cli) => frame.render_widget(cli.widget(), chunks[1]),
None => (),
};
frame.render_widget(room_info_panel, right_chunks[0]); frame.render_widget(room_info_panel, right_chunks[0]);
})?; })?;