Show source/destination disk info

This commit is contained in:
2Shirt 2024-11-12 23:23:07 -08:00
parent 2a5167bf52
commit 6c76021bf4
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
3 changed files with 178 additions and 49 deletions

View file

@ -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<UnboundedSender<Action>>,
config: Config,
cur_mode: Mode,
disks: Vec<Disk>,
list_disks: StatefulList<Disk>,
list_parts: StatefulList<Partition>,
table_type: Option<PartitionTableType>,
prev_mode: Mode,
all_modes: Vec<Mode>,
selections: Vec<Option<usize>>,
}
@ -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(())

View file

@ -39,6 +39,10 @@ impl<T: Clone> StatefulList<T> {
}
}
pub fn get_ref(&self, index: usize) -> Option<&T> {
self.items.get(index)
}
pub fn get_selected(&self) -> Option<T> {
if let Some(i) = self.state.selected() {
Some(self.items[i].clone())

View file

@ -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<Disk> {
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> {
},
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> {
},
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> {
},
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> {
},
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 {