From a77bf0c9c65ebd3fd3c610cf4b26d1700b80dd41 Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Sat, 18 Jan 2025 17:38:09 -0800 Subject: [PATCH] Refactor left pane Just use Strings instead of the various structs --- deja_vu/src/action.rs | 19 +- deja_vu/src/app.rs | 256 +++++++++++++------- deja_vu/src/components/left.rs | 415 +++++++++----------------------- deja_vu/src/components/right.rs | 32 ++- deja_vu/src/state.rs | 9 +- 5 files changed, 313 insertions(+), 418 deletions(-) diff --git a/deja_vu/src/action.rs b/deja_vu/src/action.rs index b007f1b..090d974 100644 --- a/deja_vu/src/action.rs +++ b/deja_vu/src/action.rs @@ -16,15 +16,7 @@ use serde::{Deserialize, Serialize}; use strum::Display; -use crate::{ - components::popup::Type, - line::DVLine, - state::Mode, - system::{ - disk::{Disk, PartitionTableType}, - drivers::Driver, - }, -}; +use crate::{components::popup::Type, line::DVLine, state::Mode, system::disk::Disk}; #[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)] pub enum Action { @@ -33,12 +25,11 @@ pub enum Action { InstallDriver, Process, ScanDisks, - Select(Option, Option), // indicies for (source, dest) or (boot, os) - SelectDriver(Driver), - SelectTableType(PartitionTableType), + Select(Option, Option), // indicies for (source, dest) etc + SelectRight(Option, Option), // indicies for right info pane UpdateDiskList(Vec), - UpdateLeft(Vec>, usize, Vec>), // (labels, start_index, lines) - lines before start are always shown - UpdateRight(Vec>, usize, Vec>), // Same as above + UpdateLeft(String, Vec, Vec, bool), // (title, labels, items, select_one) + UpdateRight(Vec>, usize, Vec>), // (labels, start_index, items) - items before start are always shown // Screens DismissPopup, DisplayPopup(Type, String), diff --git a/deja_vu/src/app.rs b/deja_vu/src/app.rs index 8a472b6..84844f8 100644 --- a/deja_vu/src/app.rs +++ b/deja_vu/src/app.rs @@ -101,44 +101,43 @@ impl App { }) } - pub fn next_mode(&mut self) -> (Option, Option) { - let new_mode = match (self.prev_mode, self.cur_mode) { - (_, Mode::InstallDrivers) => Mode::ScanDisks, - (_, Mode::ScanDisks) => Mode::SelectDisks, - (_, Mode::SelectDisks | Mode::SelectTableType | Mode::SelectParts) => { - if self.selections[1].is_some() { - Mode::Confirm - } else { - self.cur_mode - } - } - (Mode::SelectDisks, Mode::Confirm) => Mode::SelectTableType, - (Mode::SelectTableType, Mode::Confirm) => Mode::PreClone, - (_, Mode::PreClone) => Mode::Clone, - (_, Mode::Clone) => Mode::SelectParts, - (Mode::SelectParts, Mode::Confirm) => Mode::PostClone, - (_, Mode::PostClone | Mode::Done) => Mode::Done, - (_, Mode::Failed) => Mode::Failed, - // Invalid states - (_, Mode::Confirm) => panic!("This shouldn't happen."), + pub fn prev_mode(&mut self) -> Option { + let new_mode = match self.cur_mode { + Mode::Failed => Some(Mode::Failed), + Mode::Done => Some(Mode::Done), + Mode::SelectParts => Some(Mode::SelectParts), + Mode::Confirm => Some(Mode::SelectTableType), + Mode::SelectTableType => Some(Mode::SelectDisks), + Mode::SelectDisks => Some(Mode::ScanDisks), + // + Mode::InstallDrivers + | Mode::ScanDisks + | Mode::PreClone + | Mode::Clone + | Mode::PostClone => None, }; + new_mode + } - let prev_mode = { - match self.cur_mode { - Mode::Confirm => Some(self.prev_mode), - Mode::PreClone | Mode::Clone | Mode::PostClone | Mode::Done => { - // Override since we're past the point of no return - Some(self.cur_mode) - } - _ => Some(self.cur_mode), - } + pub fn next_mode(&mut self) -> Option { + let new_mode = match self.cur_mode { + Mode::InstallDrivers => Mode::ScanDisks, + Mode::ScanDisks => Mode::SelectDisks, + Mode::SelectDisks => Mode::SelectTableType, + Mode::SelectTableType => Mode::Confirm, + Mode::Confirm => Mode::PreClone, + Mode::PreClone => Mode::Clone, + Mode::Clone => Mode::SelectParts, + Mode::SelectParts => Mode::PostClone, + Mode::PostClone | Mode::Done => Mode::Done, + Mode::Failed => Mode::Failed, }; if new_mode == self.cur_mode { // No mode change needed - (None, None) + None } else { - (prev_mode, Some(new_mode)) + Some(new_mode) } } @@ -146,6 +145,7 @@ impl App { info!("Setting mode to {new_mode:?}"); self.cur_mode = new_mode; match new_mode { + Mode::InstallDrivers => self.clone.scan_drivers(), Mode::ScanDisks => { self.prev_mode = self.cur_mode; if self.tasks.idle() { @@ -244,10 +244,7 @@ impl App { String::from("COMPLETE\n\n\nThank you for using this tool!"), ))?; } - _ => { - //TODO - //FIXME - } + _ => {} } Ok(()) } @@ -361,37 +358,41 @@ impl App { Action::InstallDriver => { self.action_tx.send(Action::SetMode(Mode::InstallDrivers))?; } - Action::SelectDriver(ref driver) => { - self.clone.driver = Some(driver.clone()); - drivers::load(&driver.inf_paths); - self.action_tx.send(Action::NextScreen)?; - } - Action::SelectTableType(ref table_type) => { - self.clone.table_type = Some(table_type.clone()); - self.action_tx.send(Action::NextScreen)?; - } + Action::Process => match self.cur_mode { + Mode::Confirm => { + self.action_tx.send(Action::NextScreen)?; + } + _ => {} + }, Action::Resize(w, h) => self.handle_resize(tui, w, h)?, Action::Render => self.render(tui)?, Action::PrevScreen => { - let new_mode = match (self.prev_mode, self.cur_mode) { - (Mode::SelectTableType, Mode::SelectTableType) => Mode::SelectDisks, - (_, _) => self.prev_mode, - }; - self.action_tx.send(Action::SetMode(new_mode))?; + if let Some(new_mode) = self.prev_mode() { + self.prev_mode = new_mode; + self.cur_mode = new_mode; + self.action_tx.send(Action::SetMode(new_mode))?; + } } Action::NextScreen => match self.next_mode() { - (None, None) => {} - (Some(prev), Some(next)) => { - self.prev_mode = prev; + None => {} + Some(next) => { + self.prev_mode = self.cur_mode; self.cur_mode = next; self.action_tx.send(Action::DismissPopup)?; self.action_tx.send(Action::SetMode(next))?; } - _ => panic!("Failed to determine next mode"), }, Action::ScanDisks => self.action_tx.send(Action::SetMode(Mode::ScanDisks))?, Action::Select(one, two) => { match self.cur_mode { + Mode::InstallDrivers => { + if let Some(index) = one { + if let Some(driver) = self.clone.driver_list.get(index).cloned() { + drivers::load(&driver.inf_paths); + self.clone.driver = Some(driver); + } + } + } Mode::SelectDisks => { self.clone.disk_index_source = one; self.clone.disk_index_dest = two; @@ -400,6 +401,21 @@ impl App { self.clone.part_index_boot = one; self.clone.part_index_os = two; } + Mode::SelectTableType => { + self.clone.table_type = { + if let Some(index) = one { + match index { + 0 => Some(PartitionTableType::Guid), + 1 => Some(PartitionTableType::Legacy), + index => { + panic!("Failed to select PartitionTableType: {}", index) + } + } + } else { + None + } + } + } _ => {} } self.selections[0] = one; @@ -407,13 +423,22 @@ impl App { } Action::SetMode(new_mode) => { self.set_mode(new_mode)?; - let (labels, start, lines) = - get_right_selections(self, self.prev_mode, self.cur_mode); + let (title, labels, items, select_one) = build_left_items(self, self.cur_mode); self.action_tx - .send(Action::UpdateRight(labels, start, lines))?; + .send(Action::UpdateLeft(title, labels, items, select_one))?; + let (labels, start, items) = build_right_items(self, self.cur_mode); + self.action_tx + .send(Action::UpdateRight(labels, start, items))?; match new_mode { - Mode::InstallDrivers | Mode::SelectDisks => { - self.action_tx.send(Action::Select(None, None))? + // Mode::InstallDrivers | Mode::SelectDisks => { + // self.action_tx.send(Action::Select(None, None))? + // } + Mode::SelectTableType | Mode::Confirm => { + // Select source/dest disks + self.action_tx.send(Action::SelectRight( + self.clone.disk_index_source, + self.clone.disk_index_dest, + ))?; } Mode::SelectParts => { // Select first partition as boot partition @@ -525,28 +550,76 @@ fn get_chunks(r: Rect) -> Vec { chunks } -fn get_right_selections( - app: &App, - prev_mode: Mode, - cur_mode: Mode, -) -> (Vec>, usize, Vec>) { +fn build_left_items(app: &App, cur_mode: Mode) -> (String, Vec, Vec, bool) { + let title: String; + let mut items = Vec::new(); + let mut labels: Vec = Vec::new(); + let mut select_one = false; + match cur_mode { + Mode::InstallDrivers => { + title = String::from("Install Drivers"); + select_one = true; + app.clone + .driver_list + .iter() + .for_each(|driver| items.push(driver.to_string())); + } + Mode::SelectDisks => { + title = String::from("Select Source and Destination Disks"); + labels.push(String::from("source")); + labels.push(String::from("dest")); + let disk_list = app.clone.disk_list.lock().unwrap(); + disk_list + .iter() + .for_each(|disk| items.push(disk.description.to_string())); + } + Mode::SelectTableType => { + title = String::from("Select Partition Table Type"); + select_one = true; + items.push(format!("{}", PartitionTableType::Guid)); + items.push(format!("{}", PartitionTableType::Legacy)); + } + Mode::Confirm => { + title = String::from("Confirm Selections"); + } + Mode::PreClone | Mode::Clone | Mode::PostClone | Mode::ScanDisks => { + title = String::from("Processing"); + } + Mode::SelectParts => { + title = String::from("Select Boot and OS Partitions"); + labels.push(String::from("boot")); + labels.push(String::from("os")); + let disk_list = app.clone.disk_list.lock().unwrap(); + if let Some(index) = app.clone.disk_index_dest { + if let Some(disk) = disk_list.get(index) { + disk.get_parts().iter().for_each(|part| { + items.push(part.to_string()); + }); + } + } + } + Mode::Done | Mode::Failed => title = String::from("Done"), + }; + (title, labels, items, select_one) +} + +fn build_right_items(app: &App, cur_mode: Mode) -> (Vec>, usize, Vec>) { + let mut items = Vec::new(); let mut labels: Vec> = Vec::new(); - let mut selections = Vec::new(); let mut start_index = 0; - match (prev_mode, cur_mode) { - (_, Mode::InstallDrivers) => { - selections.push(vec![DVLine { + match cur_mode { + Mode::InstallDrivers => { + items.push(vec![DVLine { line_parts: vec![String::from("CPU")], line_colors: vec![Color::Cyan], }]); - selections.push(vec![DVLine { + items.push(vec![DVLine { line_parts: vec![get_cpu_name()], line_colors: vec![Color::Reset], }]); start_index = 2; } - (_, Mode::SelectDisks | Mode::SelectTableType) - | (Mode::SelectDisks | Mode::SelectTableType, Mode::Confirm) => { + Mode::SelectDisks | Mode::SelectTableType | Mode::Confirm => { // Labels labels.push(vec![DVLine { line_parts: vec![String::from("Source")], @@ -559,31 +632,28 @@ fn get_right_selections( ], line_colors: vec![Color::Cyan, Color::Red], }; - match (prev_mode, cur_mode) { - (Mode::SelectTableType, Mode::Confirm) => { - if let Some(table_type) = &app.clone.table_type { - // Show table type - let type_str = match table_type { - PartitionTableType::Guid => "GPT", - PartitionTableType::Legacy => "MBR", - }; - labels.push(vec![ - dest_dv_line, - DVLine { - line_parts: vec![format!(" (Will be formatted {type_str})")], - line_colors: vec![Color::Yellow], - }, - ]); - } - } - _ => labels.push(vec![dest_dv_line]), + if let Some(table_type) = &app.clone.table_type { + // Show table type + let type_str = match table_type { + PartitionTableType::Guid => "GPT", + PartitionTableType::Legacy => "MBR", + }; + labels.push(vec![ + dest_dv_line, + DVLine { + line_parts: vec![format!(" (Will be formatted {type_str})")], + line_colors: vec![Color::Yellow], + }, + ]); + } else { + labels.push(vec![dest_dv_line]); } let disk_list = app.clone.disk_list.lock().unwrap(); disk_list .iter() - .for_each(|disk| selections.push(get_disk_description_right(&disk))); + .for_each(|disk| items.push(get_disk_description_right(&disk))); } - (_, Mode::SelectParts) | (Mode::SelectParts, Mode::Confirm) => { + Mode::SelectParts => { vec!["Boot", "OS"].iter().for_each(|s| { labels.push(vec![DVLine { line_parts: vec![String::from(*s)], @@ -595,16 +665,16 @@ fn get_right_selections( let disk_list = app.clone.disk_list.lock().unwrap(); if let Some(disk) = disk_list.get(index) { // Disk Details - selections.push(get_disk_description_right(&disk)); + items.push(get_disk_description_right(&disk)); // Partition Details disk.parts .iter() - .for_each(|part| selections.push(get_part_description(&part))); + .for_each(|part| items.push(get_part_description(&part))); } } } _ => {} } - (labels, start_index, selections) + (labels, start_index, items) } diff --git a/deja_vu/src/components/left.rs b/deja_vu/src/components/left.rs index 7b7349c..beff17a 100644 --- a/deja_vu/src/components/left.rs +++ b/deja_vu/src/components/left.rs @@ -20,42 +20,37 @@ use ratatui::{ widgets::{Block, Borders, HighlightSpacing, List, ListItem, Padding, Paragraph}, }; use tokio::sync::mpsc::UnboundedSender; -use tracing::info; -use super::{popup, state::StatefulList, Component}; -use crate::{ - action::Action, - config::Config, - state::Mode, - system::{ - disk::{Disk, Partition, PartitionTableType}, - drivers::{self, Driver}, - }, -}; +use super::{state::StatefulList, Component}; +use crate::{action::Action, config::Config}; #[derive(Default)] pub struct Left { command_tx: Option>, config: Config, - disk_id_dest: Option, - table_type: Option, - title_text: String, - list_disks: StatefulList, - list_drivers: StatefulList, - list_parts: StatefulList, - list_table_types: StatefulList, - mode: Mode, + labels: Vec, + list: StatefulList, + select_one: bool, selections: Vec>, + selections_saved: Vec>, + title_text: String, } impl Left { pub fn new() -> Self { Self { + select_one: false, + labels: vec![String::from("one"), String::from("two")], selections: vec![None, None], + selections_saved: vec![None, None], title_text: String::from("Home"), ..Default::default() } } + + fn set_highlight(&mut self, index: usize) { + self.list.select(index); + } } impl Component for Left { @@ -76,180 +71,58 @@ impl Component for Left { fn update(&mut self, action: Action) -> Result> { match action { - Action::KeyUp => match self.mode { - Mode::InstallDrivers => self.list_drivers.previous(), - Mode::SelectDisks => self.list_disks.previous(), - Mode::SelectTableType => self.list_table_types.previous(), - Mode::SelectParts => self.list_parts.previous(), - _ => {} - }, - Action::KeyDown => match self.mode { - Mode::InstallDrivers => self.list_drivers.next(), - Mode::SelectDisks => self.list_disks.next(), - Mode::SelectTableType => self.list_table_types.next(), - Mode::SelectParts => self.list_parts.next(), - _ => {} - }, - Action::Process => match self.mode { - // NOTE: Remove all variants except Mode::Confirm? - Mode::Confirm => { - if let Some(command_tx) = self.command_tx.clone() { - command_tx.send(Action::NextScreen)?; - } - } - Mode::InstallDrivers - | Mode::SelectDisks - | Mode::SelectTableType - | Mode::SelectParts => { - // Menu selection sections - let selection: Option = match self.mode { - Mode::InstallDrivers => self.list_drivers.selected(), - Mode::SelectDisks => self.list_disks.selected(), - Mode::SelectTableType => self.list_table_types.selected(), - Mode::SelectParts => self.list_parts.selected(), - _ => panic!("This shouldn't happen!"), - }; - if let Some(index) = selection { - if let Some(command_tx) = self.command_tx.clone() { - let mut selection_one: Option = None; - let mut selection_two: Option = None; - - // Get selection(s) - if self.selections[0].is_none() { - // First selection - selection_one = Some(index); - selection_two = None; - } else { - // Second selection - if let Some(source_index) = self.selections[0] { - if index == source_index { - // Toggle first selection - selection_one = None; - self.selections[0] = None; - } else { - selection_one = self.selections[0]; - selection_two = Some(index); - } + Action::Highlight(index) => self.set_highlight(index), + Action::KeyUp => self.list.previous(), + Action::KeyDown => self.list.next(), + Action::Process => { + if let Some(command_tx) = self.command_tx.clone() { + match (self.selections[0], self.selections[1]) { + (None, None) => { + // Making first selection + command_tx.send(Action::Select(self.list.selected(), None))?; + if self.select_one { + // Confirm selection + command_tx.send(Action::NextScreen)?; + } + } + (Some(first_index), None) => { + if let Some(second_index) = self.list.selected() { + // Making second selection + if first_index == second_index { + // Toggle first selection + command_tx.send(Action::Select(None, None))?; + } else { + // Both selections made, proceed to next screen + command_tx.send(Action::Select( + Some(first_index), + Some(second_index), + ))?; + command_tx.send(Action::NextScreen)?; } } - - // Send selection(s) if needed - // NOTE: This is needed to keep the app and all components in sync - match self.mode { - Mode::InstallDrivers => { - // Only need to select one entry - if let Some(driver) = self.list_drivers.get_selected() { - command_tx.send(Action::SelectDriver(driver.clone()))?; - } - } - Mode::SelectTableType => { - // Only need to select one entry - if let Some(table_type) = self.list_table_types.get_selected() { - self.table_type = Some(table_type.clone()); - command_tx.send(Action::SelectTableType(table_type))?; - } - } - Mode::SelectDisks | Mode::SelectParts => { - command_tx - .send(Action::Select(selection_one, selection_two))?; - - // Advance screen if both selections made - if selection_two.is_some() { - command_tx.send(Action::NextScreen)?; - } - } - _ => {} - }; } + _ => panic!("This shouldn't happen?"), } } - _ => {} - }, - Action::Select(Some(index), None) => self.selections[0] = Some(index), - Action::Select(_, Some(index)) => { - if self.mode == Mode::SelectDisks { - self.disk_id_dest = Some(index); - } } - Action::SetMode(new_mode) => { - let prev_mode = self.mode; - self.mode = new_mode; - match (prev_mode, new_mode) { - (_, Mode::ScanDisks) => { - self.list_disks.clear_items(); - self.title_text = String::new(); - } - (_, Mode::InstallDrivers) => { - self.list_drivers.set_items(drivers::scan()); - self.selections[0] = None; - self.selections[1] = None; - self.title_text = String::from("Install Drivers"); - if self.list_drivers.is_empty() { - if let Some(command_tx) = self.command_tx.clone() { - command_tx.send(Action::DisplayPopup( - popup::Type::Error, - String::from("No drivers available to install"), - ))?; - } - } - } - (_, Mode::SelectDisks) => { - self.selections[0] = None; - self.selections[1] = None; - self.title_text = String::from("Select Source and Destination Disks"); - } - (_, Mode::SelectTableType) => { - self.list_table_types - .set_items(vec![PartitionTableType::Guid, PartitionTableType::Legacy]); - self.selections[0] = None; - self.selections[1] = None; - self.title_text = String::from("Select Partition Table Type"); - } - (_, Mode::PreClone | Mode::Clone | Mode::PostClone) => { - self.title_text = String::from("Processing"); - } - (_, Mode::SelectParts) => { - self.title_text = String::from("Select Boot and OS Partitions"); - } - (Mode::SelectDisks | Mode::SelectParts, Mode::Confirm) => { - self.title_text = String::from("Confirm Selections"); - } - (Mode::SelectTableType, Mode::Confirm) => { - self.title_text = String::from("Confirm Selections (Again)"); - } - (_, Mode::Done | Mode::Failed) => self.title_text = String::from("Done"), - // Invalid states - (_, Mode::Confirm) => panic!("This shouldn't happen."), - } + Action::Select(one, two) => { + self.selections[0] = one; + self.selections[1] = two; + self.selections_saved[0] = one; + self.selections_saved[1] = two; } - Action::UpdateDiskList(disks) => { - info!("Updating disk list"); - self.list_disks.set_items(disks); - if self.mode == Mode::Clone { - if let Some(index) = self.disk_id_dest { - if let Some(disk) = self.list_disks.get(index) { - self.list_parts.set_items(disk.get_parts()); - - // Auto-select first partition and highlight likely OS partition - if let Some(table_type) = &self.table_type { - match table_type { - PartitionTableType::Guid => { - if disk.num_parts() >= 3 { - self.selections[0] = Some(0); - self.list_parts.select(2); - } - } - PartitionTableType::Legacy => { - if disk.num_parts() >= 2 { - self.selections[0] = Some(0); - self.list_parts.select(1); - } - } - } - } - } - } - } + Action::SetMode(_) => { + self.selections[0] = None; + self.selections[1] = None; + } + Action::UpdateLeft(title, labels, items, select_one) => { + self.title_text = title; + self.labels = labels + .iter() + .map(|label| format!(" ~{}~", label.to_lowercase())) + .collect(); + self.list.set_items(items); + self.select_one = select_one; } _ => {} } @@ -263,126 +136,70 @@ impl Component for Left { .areas(area); // Title + let title_text = if self.selections[1].is_some() || self.select_one { + "Confirm Selections" + } else { + self.title_text.as_str() + }; let title = - Paragraph::new(Line::from(Span::styled(&self.title_text, Style::default())).centered()) + Paragraph::new(Line::from(Span::styled(title_text, Style::default())).centered()) .block(Block::default().borders(Borders::NONE)); frame.render_widget(title, title_area); - // Body - match self.mode { - Mode::ScanDisks - | Mode::PreClone - | Mode::Clone - | Mode::PostClone - | Mode::Done - | Mode::Failed => { - // Leave blank - let paragraph = Paragraph::new(String::new()).block( - Block::default() - .borders(Borders::ALL) - .padding(Padding::new(1, 1, 1, 1)), - ); - frame.render_widget(paragraph, body_area); + // Body (Blank) + if self.list.is_empty() { + // Leave blank + let paragraph = Paragraph::new(String::new()).block( + Block::default() + .borders(Borders::ALL) + .padding(Padding::new(1, 1, 1, 1)), + ); + frame.render_widget(paragraph, body_area); - // Bail early - return Ok(()); - } - Mode::Confirm => { - // Nag the user - let paragraph = Paragraph::new(String::from("Are the listed selections correct?")) - .block( - Block::default() - .borders(Borders::ALL) - .padding(Padding::new(1, 1, 1, 1)), - ); - frame.render_widget(paragraph, body_area); - - // Bail early - return Ok(()); - } - Mode::InstallDrivers - | Mode::SelectDisks - | Mode::SelectTableType - | Mode::SelectParts => { - // List modes - let mut list_items = Vec::::new(); - let list_items_strings: Vec = match self.mode { - Mode::InstallDrivers => self - .list_drivers - .items - .iter() - .map(|i| format!("{i}")) - .collect(), - Mode::SelectDisks => self - .list_disks - .items - .iter() - .map(|i| format!("{i}")) - .collect(), - Mode::SelectTableType => self - .list_table_types - .items - .iter() - .map(|i| format!("{i}")) - .collect(), - Mode::SelectParts => self - .list_parts - .items - .iter() - .map(|i| format!("{i}")) - .collect(), - _ => panic!("This shouldn't happen."), - }; - if !list_items_strings.is_empty() { - for (index, item) in list_items_strings.iter().enumerate() { - let mut item_style = Style::default(); - let mut item_text_tail = ""; - if let Some(selection_one) = self.selections[0] { - if selection_one == index { - item_style = Style::new().yellow(); - item_text_tail = match self.mode { - Mode::SelectDisks => " ~source disk~", - Mode::SelectParts => " ~boot volume~", - _ => "", - } - } - } - list_items.push( - ListItem::new(format!(" {item}\n{item_text_tail}\n\n")) - .style(item_style), - ); - } - } - let list = List::new(list_items) - .block( - Block::default() - .borders(Borders::ALL) - .padding(Padding::new(1, 1, 1, 1)), - ) - .highlight_spacing(HighlightSpacing::Always) - .highlight_style(Style::new().green().bold()) - .highlight_symbol(" --> ") - .repeat_highlight_symbol(false); - match self.mode { - Mode::InstallDrivers => { - frame.render_stateful_widget(list, body_area, &mut self.list_drivers.state); - } - Mode::SelectDisks => { - frame.render_stateful_widget(list, body_area, &mut self.list_disks.state); - } - Mode::SelectTableType => frame.render_stateful_widget( - list, - body_area, - &mut self.list_table_types.state, - ), - Mode::SelectParts => { - frame.render_stateful_widget(list, body_area, &mut self.list_parts.state); - } - _ => panic!("This shouldn't happen."), - } - } + // Bail early + return Ok(()); } + // Body + let list_items: Vec = self + .list + .items + .iter() + .enumerate() + .map(|(index, item)| { + let mut style = Style::default(); + let text = if self.selections[0].is_some_and(|first_index| first_index == index) { + if let Some(label) = self.labels.get(0) { + style = style.yellow(); + label.as_str() + } else { + "" + } + } else if self.selections[1].is_some_and(|second_index| second_index == index) { + if let Some(label) = self.labels.get(1) { + style = style.yellow(); + label.as_str() + } else { + "" + } + } else { + "" + }; + ListItem::new(format!(" {item}\n{text}\n\n")).style(style) + }) + .collect(); + let list = List::new(list_items) + .block( + Block::default() + .borders(Borders::ALL) + .padding(Padding::new(1, 1, 1, 1)), + ) + .highlight_spacing(HighlightSpacing::Always) + .highlight_style(Style::new().green().bold()) + .highlight_symbol(" --> ") + .repeat_highlight_symbol(false); + frame.render_stateful_widget(list, body_area, &mut self.list.state); + // Done Ok(()) } diff --git a/deja_vu/src/components/right.rs b/deja_vu/src/components/right.rs index 960f5af..80622c2 100644 --- a/deja_vu/src/components/right.rs +++ b/deja_vu/src/components/right.rs @@ -22,13 +22,12 @@ use ratatui::{ use tokio::sync::mpsc::UnboundedSender; use super::{state::StatefulList, Component}; -use crate::{action::Action, config::Config, line::DVLine, state::Mode}; +use crate::{action::Action, config::Config, line::DVLine}; #[derive(Default)] pub struct Right { command_tx: Option>, config: Config, - cur_mode: Mode, list_header: Vec, list_labels: Vec>, list: StatefulList>, @@ -98,13 +97,22 @@ impl Component for Right { Action::Select(one, two) => { self.selections[0] = one; self.selections[1] = two; + if self.selections_saved[1].is_none() { + // Update selections_saved + // Conversely, if both selections set then preserve previous choices + self.selections_saved[0] = one; + self.selections_saved[1] = two; + } + } + Action::SelectRight(one, two) => { self.selections_saved[0] = one; self.selections_saved[1] = two; } - Action::SetMode(new_mode) => { - self.cur_mode = new_mode; + Action::SetMode(_) => { self.selections[0] = None; self.selections[1] = None; + self.selections_saved[0] = None; + self.selections_saved[1] = None; } Action::UpdateRight(labels, start_index, list) => { self.list_header = list[..start_index].iter().flatten().cloned().collect(); @@ -142,9 +150,11 @@ impl Component for Right { // First selection if let Some(first_index) = self.get_first() { if let Some(first_desc) = self.list.get(first_index) { - self.list_labels[0] - .iter() - .for_each(|dv| body_text.push(dv.as_line().bold())); + if let Some(label) = self.list_labels.get(0) { + label + .iter() + .for_each(|dv| body_text.push(dv.as_line().bold())); + } body_text.push(Line::from("")); first_desc .iter() @@ -159,9 +169,11 @@ impl Component for Right { body_text.push(Line::from("")); body_text.push(Line::from(str::repeat("─", (body_area.width - 4) as usize))); body_text.push(Line::from("")); - self.list_labels[1] - .iter() - .for_each(|dv| body_text.push(dv.as_line().bold())); + if let Some(label) = self.list_labels.get(1) { + label + .iter() + .for_each(|dv| body_text.push(dv.as_line().bold())); + } body_text.push(Line::from("")); second_desc .iter() diff --git a/deja_vu/src/state.rs b/deja_vu/src/state.rs index 63b0abb..b3219b0 100644 --- a/deja_vu/src/state.rs +++ b/deja_vu/src/state.rs @@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize}; use crate::system::{ disk::{Disk, PartitionTableType}, - drivers::Driver, + drivers, }; #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -44,9 +44,10 @@ pub struct CloneSettings { pub disk_index_dest: Option, pub disk_index_source: Option, pub disk_list: Arc>>, + pub driver_list: Vec, pub part_index_boot: Option, pub part_index_os: Option, - pub driver: Option, + pub driver: Option, pub table_type: Option, } @@ -57,4 +58,8 @@ impl CloneSettings { ..Default::default() } } + + pub fn scan_drivers(&mut self) { + self.driver_list = drivers::scan(); + } }