handle instance select in own state

This commit is contained in:
2026-03-28 21:23:13 +01:00
parent 93676901c0
commit e70c6e6901
2 changed files with 105 additions and 75 deletions

View File

@@ -1,16 +1,20 @@
use std::io;
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
use log::error;
use ratatui::{
DefaultTerminal, Frame,
layout::{Constraint, Direction, Layout, Rect},
style::Style,
widgets::{Block, Borders, StatefulWidget, TableState, Widget},
widgets::{StatefulWidget, TableState, Widget},
};
use crate::{
tui::{instance::InstanceSelect, mod_list::ModList, status::StatusBar},
types::RootConfig,
tui::{
instance::{InstanceSelect, InstanceSelectState},
mod_list::ModList,
status::StatusBar,
},
types::{ModdedInstance, RootConfig},
};
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> {
root_config: &'a mut RootConfig,
loaded_instance: Option<ModdedInstance>,
exit: bool,
active_modal: bool,
mod_list_state: TableState,
selected_instance: Option<String>,
selected_instance_state: InstanceSelectState,
}
impl<'a> App<'a> {
fn new(root_config: &'a mut RootConfig) -> Self {
let mut state = TableState::default();
state.select(Some(0)); // select first row by default
Self {
root_config,
mod_list_state: state,
selected_instance: None,
loaded_instance: None,
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();
}
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') => {
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;
}
fn next_instance(&mut self) {
let mut instances = self.root_config.instances();
instances.sort();
if instances.is_empty() {
self.selected_instance = None;
fn load_instance(&mut self) {
let Some(selected) = self.selected_instance_state.instance() else {
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;
}
fn prev_instance(&mut self) {
let mut instances = self.root_config.instances();
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()),
}
match self.root_config.load_instance_by_id(selected) {
Ok(instance) => {
self.loaded_instance = Some(instance);
}
};
self.selected_instance = prev;
Err(err) => {
error!("Failed to load instance: {err}");
self.exit();
}
}
}
}
@@ -152,14 +122,12 @@ impl<'a> Widget for &mut App<'a> {
.constraints([
Constraint::Length(3),
Constraint::Min(1),
Constraint::Length(1), // single line for keybindings
Constraint::Length(1),
])
.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);
StatusBar.render(chunks[2], buf);
}
}