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 ratatui::{prelude::*, widgets::*};
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
use super::Component;
|
use super::{state::StatefulList, Component};
|
||||||
use crate::{action::Action, app::Mode, config::Config, system::disk::Disk};
|
use crate::{
|
||||||
|
action::Action,
|
||||||
|
app::Mode,
|
||||||
|
config::Config,
|
||||||
|
system::{
|
||||||
|
disk::{Disk, Partition, PartitionTableType},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Right {
|
pub struct Right {
|
||||||
command_tx: Option<UnboundedSender<Action>>,
|
command_tx: Option<UnboundedSender<Action>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
cur_mode: Mode,
|
cur_mode: Mode,
|
||||||
disks: Vec<Disk>,
|
list_disks: StatefulList<Disk>,
|
||||||
|
list_parts: StatefulList<Partition>,
|
||||||
|
table_type: Option<PartitionTableType>,
|
||||||
prev_mode: Mode,
|
prev_mode: Mode,
|
||||||
all_modes: Vec<Mode>,
|
|
||||||
selections: Vec<Option<usize>>,
|
selections: Vec<Option<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,18 +73,26 @@ impl Component for Right {
|
||||||
Action::Render => {
|
Action::Render => {
|
||||||
// add any logic here that should run on every 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) => {
|
Action::Select(one, two) => {
|
||||||
self.selections[0] = one;
|
self.selections[0] = one;
|
||||||
self.selections[1] = two;
|
self.selections[1] = two;
|
||||||
}
|
}
|
||||||
|
Action::SelectTableType(table_type) => self.table_type = Some(table_type),
|
||||||
Action::SetMode(new_mode) => {
|
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.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)
|
Ok(None)
|
||||||
|
|
@ -95,20 +111,131 @@ impl Component for Right {
|
||||||
frame.render_widget(title, title_area);
|
frame.render_widget(title, title_area);
|
||||||
|
|
||||||
// Body
|
// Body
|
||||||
let paragraph = Paragraph::new(format!(
|
let mut body_text = Vec::new();
|
||||||
"Prev Mode: {:?} // Cur Mode: {:?}\n{:?}\n{:?}\nDisks: {}",
|
match (self.prev_mode, self.cur_mode) {
|
||||||
self.prev_mode,
|
(_, Mode::InstallDrivers) => {
|
||||||
self.cur_mode,
|
}
|
||||||
self.all_modes,
|
(_, Mode::SelectDisks) | (Mode::SelectDisks | Mode::SelectTableType, Mode::Confirm) => {
|
||||||
self.selections,
|
// Source Disk
|
||||||
self.disks.len(),
|
body_text.push(Line::from(Span::styled(
|
||||||
))
|
"Source:",
|
||||||
.block(
|
Style::default().cyan().bold(),
|
||||||
Block::default()
|
)));
|
||||||
.borders(Borders::ALL)
|
body_text.push(Line::from(""));
|
||||||
.padding(Padding::new(1, 1, 1, 1)),
|
body_text.push(Line::from(Span::styled(
|
||||||
);
|
format!(
|
||||||
frame.render_widget(paragraph, body_area);
|
"{:<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
|
// Done
|
||||||
Ok(())
|
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> {
|
pub fn get_selected(&self) -> Option<T> {
|
||||||
if let Some(i) = self.state.selected() {
|
if let Some(i) = self.state.selected() {
|
||||||
Some(self.items[i].clone())
|
Some(self.items[i].clone())
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ use crate::system::diskpart;
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Disk {
|
pub struct Disk {
|
||||||
pub conn_type: String,
|
pub conn_type: String,
|
||||||
|
pub description: String,
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
pub model: String,
|
pub model: String,
|
||||||
pub part_type: PartitionTableType,
|
pub part_type: PartitionTableType,
|
||||||
|
|
@ -60,6 +61,7 @@ pub enum PartitionTableType {
|
||||||
|
|
||||||
impl Disk {
|
impl Disk {
|
||||||
pub fn generate_descriptions(&mut self) {
|
pub fn generate_descriptions(&mut self) {
|
||||||
|
self.description = format!("{self}");
|
||||||
for part in &self.parts {
|
for part in &self.parts {
|
||||||
self.parts_description.push(format!("{part}"));
|
self.parts_description.push(format!("{part}"));
|
||||||
}
|
}
|
||||||
|
|
@ -85,27 +87,19 @@ impl Disk {
|
||||||
|
|
||||||
impl fmt::Display for Disk {
|
impl fmt::Display for Disk {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if cfg!(windows) {
|
write!(
|
||||||
write!(
|
f,
|
||||||
f,
|
"Disk {:<3} {:>11} {:<4} {:<4} {} ({})",
|
||||||
"Disk {:<3} {:>11} {:<4} {} ({})",
|
self.id,
|
||||||
self.id,
|
bytes_to_string(&self.size),
|
||||||
bytes_to_string(&self.size),
|
self.conn_type,
|
||||||
self.conn_type,
|
match self.part_type {
|
||||||
self.model,
|
PartitionTableType::Guid => "GPT",
|
||||||
self.serial,
|
PartitionTableType::Legacy => "MBR",
|
||||||
)
|
},
|
||||||
} else {
|
self.model,
|
||||||
write!(
|
self.serial,
|
||||||
f,
|
)
|
||||||
"{:<14} {:>11} {:<4} {} ({})",
|
|
||||||
self.id,
|
|
||||||
bytes_to_string(&self.size),
|
|
||||||
self.conn_type,
|
|
||||||
self.model,
|
|
||||||
self.serial,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +161,7 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
let mut disks = vec![
|
let mut disks = vec![
|
||||||
Disk {
|
Disk {
|
||||||
conn_type: "SATA".to_string(),
|
conn_type: "SATA".to_string(),
|
||||||
id: 1,
|
id: 0,
|
||||||
model: "Samsung Evo 870".to_string(),
|
model: "Samsung Evo 870".to_string(),
|
||||||
part_type: PartitionTableType::Legacy,
|
part_type: PartitionTableType::Legacy,
|
||||||
parts: vec![
|
parts: vec![
|
||||||
|
|
@ -208,7 +202,7 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
},
|
},
|
||||||
Disk {
|
Disk {
|
||||||
conn_type: "SATA".to_string(),
|
conn_type: "SATA".to_string(),
|
||||||
id: 2,
|
id: 1,
|
||||||
model: "ADATA Garbage".to_string(),
|
model: "ADATA Garbage".to_string(),
|
||||||
part_type: PartitionTableType::Legacy,
|
part_type: PartitionTableType::Legacy,
|
||||||
parts: vec![Partition {
|
parts: vec![Partition {
|
||||||
|
|
@ -225,7 +219,7 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
},
|
},
|
||||||
Disk {
|
Disk {
|
||||||
conn_type: "NVMe".to_string(),
|
conn_type: "NVMe".to_string(),
|
||||||
id: 3,
|
id: 2,
|
||||||
model: "Crucial P3 Plus".to_string(),
|
model: "Crucial P3 Plus".to_string(),
|
||||||
part_type: PartitionTableType::Guid,
|
part_type: PartitionTableType::Guid,
|
||||||
parts: vec![
|
parts: vec![
|
||||||
|
|
@ -260,7 +254,7 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
},
|
},
|
||||||
Disk {
|
Disk {
|
||||||
conn_type: "IDE".to_string(),
|
conn_type: "IDE".to_string(),
|
||||||
id: 4,
|
id: 3,
|
||||||
model: "Fireball".to_string(),
|
model: "Fireball".to_string(),
|
||||||
part_type: PartitionTableType::Guid,
|
part_type: PartitionTableType::Guid,
|
||||||
parts: vec![
|
parts: vec![
|
||||||
|
|
@ -285,13 +279,17 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
},
|
},
|
||||||
Disk {
|
Disk {
|
||||||
conn_type: "MISC".to_string(),
|
conn_type: "MISC".to_string(),
|
||||||
id: 5,
|
id: 4,
|
||||||
part_type: PartitionTableType::Legacy,
|
part_type: PartitionTableType::Legacy,
|
||||||
model: "Iomega".to_string(),
|
model: "Iomega".to_string(),
|
||||||
serial: "000".to_string(),
|
serial: "000".to_string(),
|
||||||
size: 14,
|
size: 14,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
Disk {
|
||||||
|
id: 5,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
Disk::default(),
|
Disk::default(),
|
||||||
];
|
];
|
||||||
for disk in &mut disks {
|
for disk in &mut disks {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue