Show source/destination disk info
This commit is contained in:
parent
2a5167bf52
commit
6c76021bf4
3 changed files with 178 additions and 49 deletions
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue