handle instance select in own state
This commit is contained in:
@@ -1,16 +1,20 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
||||||
|
use log::error;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
DefaultTerminal, Frame,
|
DefaultTerminal, Frame,
|
||||||
layout::{Constraint, Direction, Layout, Rect},
|
layout::{Constraint, Direction, Layout, Rect},
|
||||||
style::Style,
|
widgets::{StatefulWidget, TableState, Widget},
|
||||||
widgets::{Block, Borders, StatefulWidget, TableState, Widget},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
tui::{instance::InstanceSelect, mod_list::ModList, status::StatusBar},
|
tui::{
|
||||||
types::RootConfig,
|
instance::{InstanceSelect, InstanceSelectState},
|
||||||
|
mod_list::ModList,
|
||||||
|
status::StatusBar,
|
||||||
|
},
|
||||||
|
types::{ModdedInstance, RootConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn run(root_config: &mut RootConfig) -> anyhow::Result<()> {
|
pub fn run(root_config: &mut RootConfig) -> anyhow::Result<()> {
|
||||||
@@ -22,24 +26,24 @@ pub fn run(root_config: &mut RootConfig) -> anyhow::Result<()> {
|
|||||||
struct App<'a> {
|
struct App<'a> {
|
||||||
root_config: &'a mut RootConfig,
|
root_config: &'a mut RootConfig,
|
||||||
|
|
||||||
|
loaded_instance: Option<ModdedInstance>,
|
||||||
|
|
||||||
exit: bool,
|
exit: bool,
|
||||||
active_modal: bool,
|
|
||||||
|
|
||||||
mod_list_state: TableState,
|
mod_list_state: TableState,
|
||||||
selected_instance: Option<String>,
|
selected_instance_state: InstanceSelectState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl<'a> App<'a> {
|
||||||
fn new(root_config: &'a mut RootConfig) -> Self {
|
fn new(root_config: &'a mut RootConfig) -> Self {
|
||||||
let mut state = TableState::default();
|
|
||||||
state.select(Some(0)); // select first row by default
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
root_config,
|
root_config,
|
||||||
mod_list_state: state,
|
|
||||||
selected_instance: None,
|
loaded_instance: None,
|
||||||
|
|
||||||
exit: false,
|
exit: false,
|
||||||
active_modal: false,
|
mod_list_state: TableState::default(),
|
||||||
|
selected_instance_state: InstanceSelectState::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,10 +80,12 @@ impl<'a> App<'a> {
|
|||||||
self.mod_list_state.select_next();
|
self.mod_list_state.select_next();
|
||||||
}
|
}
|
||||||
KeyCode::Right | KeyCode::Char('l') => {
|
KeyCode::Right | KeyCode::Char('l') => {
|
||||||
self.next_instance();
|
self.selected_instance_state.next_instance(self.root_config);
|
||||||
|
self.load_instance();
|
||||||
}
|
}
|
||||||
KeyCode::Left | KeyCode::Char('h') => {
|
KeyCode::Left | KeyCode::Char('h') => {
|
||||||
self.prev_instance();
|
self.selected_instance_state.prev_instance(self.root_config);
|
||||||
|
self.load_instance();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -89,56 +95,20 @@ impl<'a> App<'a> {
|
|||||||
self.exit = true;
|
self.exit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_instance(&mut self) {
|
fn load_instance(&mut self) {
|
||||||
let mut instances = self.root_config.instances();
|
let Some(selected) = self.selected_instance_state.instance() else {
|
||||||
instances.sort();
|
|
||||||
|
|
||||||
if instances.is_empty() {
|
|
||||||
self.selected_instance = None;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
let next = match &self.selected_instance {
|
|
||||||
None => instances.first().cloned(),
|
|
||||||
Some(curr) => {
|
|
||||||
let idx = instances.iter().position(|x| x == curr);
|
|
||||||
match idx {
|
|
||||||
Some(i) => {
|
|
||||||
let next_index = (i + 1) % instances.len();
|
|
||||||
instances.get(next_index).cloned()
|
|
||||||
}
|
|
||||||
None => instances.first().cloned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.selected_instance = next;
|
match self.root_config.load_instance_by_id(selected) {
|
||||||
|
Ok(instance) => {
|
||||||
|
self.loaded_instance = Some(instance);
|
||||||
}
|
}
|
||||||
|
Err(err) => {
|
||||||
fn prev_instance(&mut self) {
|
error!("Failed to load instance: {err}");
|
||||||
let mut instances = self.root_config.instances();
|
self.exit();
|
||||||
instances.sort();
|
|
||||||
|
|
||||||
if instances.is_empty() {
|
|
||||||
self.selected_instance = None;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let prev = match &self.selected_instance {
|
|
||||||
None => instances.last().cloned(),
|
|
||||||
Some(curr) => {
|
|
||||||
let idx = instances.iter().position(|x| x == curr);
|
|
||||||
match idx {
|
|
||||||
Some(i) => {
|
|
||||||
let prev_index = if i == 0 { instances.len() - 1 } else { i - 1 };
|
|
||||||
instances.get(prev_index).cloned()
|
|
||||||
}
|
|
||||||
None => Some(instances[instances.len() - 1].clone()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
self.selected_instance = prev;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,14 +122,12 @@ impl<'a> Widget for &mut App<'a> {
|
|||||||
.constraints([
|
.constraints([
|
||||||
Constraint::Length(3),
|
Constraint::Length(3),
|
||||||
Constraint::Min(1),
|
Constraint::Min(1),
|
||||||
Constraint::Length(1), // single line for keybindings
|
Constraint::Length(1),
|
||||||
])
|
])
|
||||||
.split(area);
|
.split(area);
|
||||||
|
|
||||||
InstanceSelect::new(self.selected_instance.clone()).render(chunks[0], buf);
|
InstanceSelect {}.render(chunks[0], buf, &mut self.selected_instance_state);
|
||||||
|
|
||||||
ModList::new(self.root_config).render(chunks[1], buf, &mut self.mod_list_state);
|
ModList::new(self.root_config).render(chunks[1], buf, &mut self.mod_list_state);
|
||||||
|
|
||||||
StatusBar.render(chunks[2], buf);
|
StatusBar.render(chunks[2], buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,91 @@
|
|||||||
use ratatui::{
|
use ratatui::{
|
||||||
|
buffer::Buffer,
|
||||||
|
layout::Rect,
|
||||||
style::Style,
|
style::Style,
|
||||||
widgets::{Block, Borders, Paragraph, Widget},
|
widgets::{Block, Borders, Paragraph, StatefulWidget, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct InstanceSelect {
|
use crate::types::RootConfig;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InstanceSelectState {
|
||||||
selected: Option<String>,
|
selected: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstanceSelect {
|
impl InstanceSelectState {
|
||||||
pub fn new(selected: Option<String>) -> Self {
|
pub fn new() -> Self {
|
||||||
Self { selected }
|
Self { selected: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn instance(&self) -> Option<&str> {
|
||||||
|
self.selected.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_instance(&mut self, root_config: &RootConfig) {
|
||||||
|
let mut instances = root_config.instances();
|
||||||
|
instances.sort();
|
||||||
|
|
||||||
|
if instances.is_empty() {
|
||||||
|
self.selected = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next = match &self.selected {
|
||||||
|
None => instances.first().cloned(),
|
||||||
|
Some(curr) => {
|
||||||
|
let idx = instances.iter().position(|x| x == curr);
|
||||||
|
match idx {
|
||||||
|
Some(i) => {
|
||||||
|
let next_index = (i + 1) % instances.len();
|
||||||
|
instances.get(next_index).cloned()
|
||||||
|
}
|
||||||
|
None => instances.first().cloned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.selected = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prev_instance(&mut self, root_config: &RootConfig) {
|
||||||
|
let mut instances = root_config.instances();
|
||||||
|
instances.sort();
|
||||||
|
|
||||||
|
if instances.is_empty() {
|
||||||
|
self.selected = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev = match &self.selected {
|
||||||
|
None => instances.last().cloned(),
|
||||||
|
Some(curr) => {
|
||||||
|
let idx = instances.iter().position(|x| x == curr);
|
||||||
|
match idx {
|
||||||
|
Some(i) => {
|
||||||
|
let prev_index = if i == 0 { instances.len() - 1 } else { i - 1 };
|
||||||
|
instances.get(prev_index).cloned()
|
||||||
|
}
|
||||||
|
None => Some(instances[instances.len() - 1].clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.selected = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for InstanceSelect {
|
pub struct InstanceSelect {}
|
||||||
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
|
|
||||||
where
|
impl StatefulWidget for InstanceSelect {
|
||||||
Self: Sized,
|
type State = InstanceSelectState;
|
||||||
{
|
|
||||||
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||||
let list_block = Block::default()
|
let list_block = Block::default()
|
||||||
.title("Instance")
|
.title("Instance")
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.style(Style::default());
|
.style(Style::default());
|
||||||
|
|
||||||
Paragraph::new(self.selected.unwrap_or("None".to_owned()))
|
Paragraph::new(state.selected.clone().unwrap_or("None".to_owned()))
|
||||||
.block(list_block)
|
.block(list_block)
|
||||||
.render(area, buf);
|
.render(area, buf);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user