From 6c76021bf4da8906fd193a95e3a973ba326ae4b6 Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Tue, 12 Nov 2024 23:23:07 -0800 Subject: [PATCH] Show source/destination disk info --- src/components/right.rs | 173 ++++++++++++++++++++++++++++++++++------ src/components/state.rs | 4 + src/system/disk.rs | 50 ++++++------ 3 files changed, 178 insertions(+), 49 deletions(-) diff --git a/src/components/right.rs b/src/components/right.rs index ad9f43b..15306a4 100644 --- a/src/components/right.rs +++ b/src/components/right.rs @@ -18,17 +18,25 @@ use crossterm::event::KeyEvent; use ratatui::{prelude::*, widgets::*}; use tokio::sync::mpsc::UnboundedSender; -use super::Component; -use crate::{action::Action, app::Mode, config::Config, system::disk::Disk}; +use super::{state::StatefulList, Component}; +use crate::{ + action::Action, + app::Mode, + config::Config, + system::{ + disk::{Disk, Partition, PartitionTableType}, + }, +}; #[derive(Default)] pub struct Right { command_tx: Option>, config: Config, cur_mode: Mode, - disks: Vec, + list_disks: StatefulList, + list_parts: StatefulList, + table_type: Option, prev_mode: Mode, - all_modes: Vec, selections: Vec>, } @@ -65,18 +73,26 @@ impl Component for Right { Action::Render => { // add any logic here that should run on every render } + Action::KeyUp => match self.cur_mode { + Mode::SelectDisks => self.list_disks.previous(), + Mode::SelectParts => self.list_parts.previous(), + _ => {} + }, + Action::KeyDown => match self.cur_mode { + Mode::SelectDisks => self.list_disks.next(), + Mode::SelectParts => self.list_parts.next(), + _ => {} + }, Action::Select(one, two) => { self.selections[0] = one; self.selections[1] = two; } + Action::SelectTableType(table_type) => self.table_type = Some(table_type), Action::SetMode(new_mode) => { - if self.cur_mode != Mode::Confirm { - self.prev_mode = self.cur_mode; - } + self.prev_mode = self.cur_mode; self.cur_mode = new_mode; - self.all_modes.push(new_mode); } - Action::UpdateDiskList(disks) => self.disks = disks, + Action::UpdateDiskList(disks) => self.list_disks.set_items(disks), _ => {} } Ok(None) @@ -95,20 +111,131 @@ impl Component for Right { frame.render_widget(title, title_area); // Body - let paragraph = Paragraph::new(format!( - "Prev Mode: {:?} // Cur Mode: {:?}\n{:?}\n{:?}\nDisks: {}", - self.prev_mode, - self.cur_mode, - self.all_modes, - self.selections, - self.disks.len(), - )) - .block( - Block::default() - .borders(Borders::ALL) - .padding(Padding::new(1, 1, 1, 1)), - ); - frame.render_widget(paragraph, body_area); + let mut body_text = Vec::new(); + match (self.prev_mode, self.cur_mode) { + (_, Mode::InstallDrivers) => { + } + (_, Mode::SelectDisks) | (Mode::SelectDisks | Mode::SelectTableType, Mode::Confirm) => { + // Source Disk + body_text.push(Line::from(Span::styled( + "Source:", + Style::default().cyan().bold(), + ))); + body_text.push(Line::from("")); + body_text.push(Line::from(Span::styled( + format!( + "{:<8} {:>11} {:<4} {:<4} {}", + "Disk ID", "Size", "Conn", "Type", "Model (Serial)" + ), + Style::new().green().bold(), + ))); + let index = if self.selections[0].is_some() { + self.selections[0] + } else { + self.list_disks.selected() + }; + if let Some(i) = index { + if let Some(disk) = self.list_disks.get_ref(i) { + body_text.push(Line::from(Span::raw(&disk.description))); + + // Source parts + body_text.push(Line::from("")); + body_text.push(Line::from(Span::styled( + format!( + "{:<8} {:>11} {:<7} {}", + "Part ID", "Size", "(FS)", "\"Label\"" + ), + Style::new().blue().bold(), + ))); + for line in &disk.parts_description { + body_text.push(Line::from(Span::raw(line))); + } + } + } + + // Destination Disk + let index = match (self.selections[0], self.selections[1]) { + (Some(one), None) => { + // First selected + if let Some(two) = self.selections[1] { + if one != two { + self.selections[1] + } else { + None + } + } else { + self.list_disks.selected() + } + } + (Some(_), Some(_)) => { + // Both selected + self.selections[1] + } + (_, _) => None, + }; + if let Some(i) = index { + // Divider + body_text.push(Line::from("")); + body_text.push(Line::from(str::repeat("─", (body_area.width - 4) as usize))); + body_text.push(Line::from("")); + + // Disk + if let Some(disk) = self.list_disks.get_ref(i) { + body_text.push(Line::from(vec![ + Span::styled("Dest:", Style::default().cyan().bold()), + Span::styled( + " (WARNING: ALL DATA WILL BE DELETED!)", + Style::default().red().bold(), + ), + ])); + if let Some(table_type) = &self.table_type { + body_text.push(Line::from(Span::styled( + format!(" (Will be formatted {})", table_type), + Style::default().yellow().bold(), + ))); + } + body_text.push(Line::from("")); + body_text.push(Line::from(Span::styled( + format!( + "{:<8} {:>11} {:<4} {:<4} {}", + "Disk ID", "Size", "Conn", "Type", "Model (Serial)" + ), + Style::new().green().bold(), + ))); + body_text.push(Line::from(Span::raw(&disk.description))); + + // Destination parts + body_text.push(Line::from("")); + body_text.push(Line::from(Span::styled( + format!( + "{:<8} {:>11} {:<7} {}", + "Part ID", "Size", "(FS)", "\"Label\"" + ), + Style::new().blue().bold(), + ))); + for line in &disk.parts_description { + body_text.push(Line::from(Span::raw(line))); + } + } + } + } + (_, Mode::SelectTableType) => { + // + } + (_, Mode::SelectParts) | (Mode::SelectParts, Mode::Confirm) => { + // + } + _ => {} + } + let body = Paragraph::new(body_text) + .style(Style::default().fg(Color::Gray)) + .wrap(Wrap { trim: false }) + .block( + Block::default() + .borders(Borders::ALL) + .padding(Padding::new(1, 1, 1, 1)), + ); + frame.render_widget(body, body_area); // Done Ok(()) diff --git a/src/components/state.rs b/src/components/state.rs index fbd858b..24cc056 100644 --- a/src/components/state.rs +++ b/src/components/state.rs @@ -39,6 +39,10 @@ impl StatefulList { } } + pub fn get_ref(&self, index: usize) -> Option<&T> { + self.items.get(index) + } + pub fn get_selected(&self) -> Option { if let Some(i) = self.state.selected() { Some(self.items[i].clone()) diff --git a/src/system/disk.rs b/src/system/disk.rs index 213dfa9..6dc005c 100644 --- a/src/system/disk.rs +++ b/src/system/disk.rs @@ -30,6 +30,7 @@ use crate::system::diskpart; #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct Disk { pub conn_type: String, + pub description: String, pub id: usize, pub model: String, pub part_type: PartitionTableType, @@ -60,6 +61,7 @@ pub enum PartitionTableType { impl Disk { pub fn generate_descriptions(&mut self) { + self.description = format!("{self}"); for part in &self.parts { self.parts_description.push(format!("{part}")); } @@ -85,27 +87,19 @@ impl Disk { impl fmt::Display for Disk { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if cfg!(windows) { - write!( - f, - "Disk {:<3} {:>11} {:<4} {} ({})", - self.id, - bytes_to_string(&self.size), - self.conn_type, - self.model, - self.serial, - ) - } else { - write!( - f, - "{:<14} {:>11} {:<4} {} ({})", - self.id, - bytes_to_string(&self.size), - self.conn_type, - self.model, - self.serial, - ) - } + write!( + f, + "Disk {:<3} {:>11} {:<4} {:<4} {} ({})", + self.id, + bytes_to_string(&self.size), + self.conn_type, + match self.part_type { + PartitionTableType::Guid => "GPT", + PartitionTableType::Legacy => "MBR", + }, + self.model, + self.serial, + ) } } @@ -167,7 +161,7 @@ pub fn get_fake_disks() -> Vec { let mut disks = vec![ Disk { conn_type: "SATA".to_string(), - id: 1, + id: 0, model: "Samsung Evo 870".to_string(), part_type: PartitionTableType::Legacy, parts: vec![ @@ -208,7 +202,7 @@ pub fn get_fake_disks() -> Vec { }, Disk { conn_type: "SATA".to_string(), - id: 2, + id: 1, model: "ADATA Garbage".to_string(), part_type: PartitionTableType::Legacy, parts: vec![Partition { @@ -225,7 +219,7 @@ pub fn get_fake_disks() -> Vec { }, Disk { conn_type: "NVMe".to_string(), - id: 3, + id: 2, model: "Crucial P3 Plus".to_string(), part_type: PartitionTableType::Guid, parts: vec![ @@ -260,7 +254,7 @@ pub fn get_fake_disks() -> Vec { }, Disk { conn_type: "IDE".to_string(), - id: 4, + id: 3, model: "Fireball".to_string(), part_type: PartitionTableType::Guid, parts: vec![ @@ -285,13 +279,17 @@ pub fn get_fake_disks() -> Vec { }, Disk { conn_type: "MISC".to_string(), - id: 5, + id: 4, part_type: PartitionTableType::Legacy, model: "Iomega".to_string(), serial: "000".to_string(), size: 14, ..Default::default() }, + Disk { + id: 5, + ..Default::default() + }, Disk::default(), ]; for disk in &mut disks {