Add WIM file selection section

This commit is contained in:
2Shirt 2025-11-29 01:52:23 -08:00
parent 70525ae6e0
commit 89e768e3a4
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
7 changed files with 156 additions and 45 deletions

View file

@ -657,8 +657,9 @@ fn build_footer_string(cur_mode: Mode) -> String {
| Mode::PEMenu | Mode::PEMenu
| Mode::PreClone | Mode::PreClone
| Mode::PostClone | Mode::PostClone
| Mode::ScanWinImages | Mode::ScanWinSources
| Mode::SelectTableType | Mode::SelectTableType
| Mode::SelectWinSource
| Mode::SelectWinImage | Mode::SelectWinImage
| Mode::SetUserName => { | Mode::SetUserName => {
panic!("This shouldn't happen?") panic!("This shouldn't happen?")
@ -774,7 +775,8 @@ fn build_left_items(app: &App) -> Action {
| Mode::PreClone | Mode::PreClone
| Mode::Clone | Mode::Clone
| Mode::PostClone | Mode::PostClone
| Mode::ScanWinImages | Mode::ScanWinSources
| Mode::SelectWinSource
| Mode::SelectWinImage | Mode::SelectWinImage
| Mode::SetUserName => { | Mode::SetUserName => {
panic!("This shouldn't happen?") panic!("This shouldn't happen?")

View file

@ -188,7 +188,7 @@
"<Ctrl-c>": "Quit", "<Ctrl-c>": "Quit",
"<Ctrl-z>": "Suspend" "<Ctrl-z>": "Suspend"
}, },
"ScanWinImages": { "ScanWinSources": {
"<Enter>": "Process", "<Enter>": "Process",
"<n>": "FindWimNetwork", "<n>": "FindWimNetwork",
"<q>": "Quit", "<q>": "Quit",
@ -196,6 +196,15 @@
"<Ctrl-c>": "Quit", "<Ctrl-c>": "Quit",
"<Ctrl-z>": "Suspend" "<Ctrl-z>": "Suspend"
}, },
"SelectWinSource": {
"<Enter>": "Process",
"<Up>": "KeyUp",
"<Down>": "KeyDown",
"<q>": "Quit",
"<Ctrl-d>": "Quit",
"<Ctrl-c>": "Quit",
"<Ctrl-z>": "Suspend"
},
"SelectWinImage": { "SelectWinImage": {
"<Enter>": "Process", "<Enter>": "Process",
"<Up>": "KeyUp", "<Up>": "KeyUp",

View file

@ -43,7 +43,8 @@ pub enum Mode {
SelectParts, SelectParts,
PostClone, PostClone,
// Windows Installer // Windows Installer
ScanWinImages, ScanWinSources,
SelectWinSource,
SelectWinImage, SelectWinImage,
SetUserName, SetUserName,
// WinPE // WinPE

View file

@ -129,7 +129,8 @@ impl App {
| Mode::LogView | Mode::LogView
| Mode::PEMenu | Mode::PEMenu
| Mode::Process | Mode::Process
| Mode::ScanWinImages | Mode::ScanWinSources
| Mode::SelectWinSource
| Mode::SelectWinImage | Mode::SelectWinImage
| Mode::SetBootMode | Mode::SetBootMode
| Mode::SetUserName => panic!("This shouldn't happen?"), | Mode::SetUserName => panic!("This shouldn't happen?"),
@ -157,7 +158,8 @@ impl App {
| Mode::LogView | Mode::LogView
| Mode::PEMenu | Mode::PEMenu
| Mode::Process | Mode::Process
| Mode::ScanWinImages | Mode::ScanWinSources
| Mode::SelectWinSource
| Mode::SelectWinImage | Mode::SelectWinImage
| Mode::SetBootMode | Mode::SetBootMode
| Mode::SetUserName => panic!("This shouldn't happen?"), | Mode::SetUserName => panic!("This shouldn't happen?"),
@ -639,7 +641,8 @@ fn build_footer_string(cur_mode: Mode) -> String {
| Mode::LogView | Mode::LogView
| Mode::PEMenu | Mode::PEMenu
| Mode::Process | Mode::Process
| Mode::ScanWinImages | Mode::ScanWinSources
| Mode::SelectWinSource
| Mode::SelectWinImage | Mode::SelectWinImage
| Mode::SetBootMode | Mode::SetBootMode
| Mode::SetUserName => panic!("This shouldn't happen?"), | Mode::SetUserName => panic!("This shouldn't happen?"),
@ -715,7 +718,8 @@ fn build_left_items(app: &App) -> Action {
| Mode::LogView | Mode::LogView
| Mode::PEMenu | Mode::PEMenu
| Mode::Process | Mode::Process
| Mode::ScanWinImages | Mode::ScanWinSources
| Mode::SelectWinSource
| Mode::SelectWinImage | Mode::SelectWinImage
| Mode::SetBootMode | Mode::SetBootMode
| Mode::SetUserName => panic!("This shouldn't happen?"), | Mode::SetUserName => panic!("This shouldn't happen?"),

View file

@ -102,8 +102,9 @@ impl App {
Mode::Home | Mode::InstallDrivers => Mode::ScanDisks, Mode::Home | Mode::InstallDrivers => Mode::ScanDisks,
Mode::ScanDisks => Mode::SelectDisks, Mode::ScanDisks => Mode::SelectDisks,
Mode::SelectDisks => Mode::SelectTableType, Mode::SelectDisks => Mode::SelectTableType,
Mode::SelectTableType => Mode::ScanWinImages, Mode::SelectTableType => Mode::ScanWinSources,
Mode::ScanWinImages => Mode::SelectWinImage, Mode::ScanWinSources => Mode::SelectWinSource,
Mode::SelectWinSource => Mode::SelectWinImage,
Mode::SelectWinImage => Mode::SetUserName, Mode::SelectWinImage => Mode::SetUserName,
Mode::SetUserName => Mode::Confirm, Mode::SetUserName => Mode::Confirm,
Mode::Confirm => Mode::Process, // i.e. format, apply, etc Mode::Confirm => Mode::Process, // i.e. format, apply, etc
@ -144,7 +145,7 @@ impl App {
String::from("Scanning Disks..."), String::from("Scanning Disks..."),
))?; ))?;
} }
Mode::ScanWinImages => self.state.scan_wim_local(), Mode::ScanWinSources => self.state.scan_wim_local(),
Mode::Done => { Mode::Done => {
self.action_tx self.action_tx
.send(Action::DisplayPopup(popup::Type::Success, popup::fortune()))?; .send(Action::DisplayPopup(popup::Type::Success, popup::fortune()))?;
@ -297,12 +298,13 @@ impl App {
self.action_tx.send(Action::SetMode(Mode::SelectDisks))?; self.action_tx.send(Action::SetMode(Mode::SelectDisks))?;
} }
Mode::SetUserName => { Mode::SetUserName => {
self.action_tx.send(Action::SetMode(Mode::SelectWinImage))?; self.action_tx
.send(Action::SetMode(Mode::SelectWinSource))?;
} }
_ => {} _ => {}
}, },
Action::Process => match self.cur_mode { Action::Process => match self.cur_mode {
Mode::Confirm | Mode::ScanWinImages => { Mode::Confirm | Mode::ScanWinSources => {
self.action_tx.send(Action::NextScreen)?; self.action_tx.send(Action::NextScreen)?;
} }
Mode::Done => { Mode::Done => {
@ -338,7 +340,7 @@ impl App {
} }
} }
} }
Mode::SelectWinImage => { Mode::SelectWinSource => {
// TODO: FIXME // TODO: FIXME
// PLAN: Abuse Action::Select to send (file_index, image_index) to set all at once // PLAN: Abuse Action::Select to send (file_index, image_index) to set all at once
// self.state.wim_file_index = TODO; // self.state.wim_file_index = TODO;
@ -399,8 +401,9 @@ fn build_footer_string(cur_mode: Mode) -> String {
"(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit", "(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit",
), ),
Mode::SelectTableType => String::from("(Enter) to select / (b) to go back / (q) to quit"), Mode::SelectTableType => String::from("(Enter) to select / (b) to go back / (q) to quit"),
Mode::SelectWinSource => String::from("(Enter) to select / (q) to quit"),
Mode::SelectWinImage => String::from("(Enter) to select / (q) to quit"), Mode::SelectWinImage => String::from("(Enter) to select / (q) to quit"),
Mode::ScanWinImages => { Mode::ScanWinSources => {
String::from("(Enter) to continue / (n) to scan network / (q) to quit") String::from("(Enter) to continue / (n) to scan network / (q) to quit")
} }
Mode::SetUserName => String::from("(Enter) to continue / (Esc) to go back"), Mode::SetUserName => String::from("(Enter) to continue / (Esc) to go back"),
@ -445,15 +448,25 @@ fn build_left_items(app: &App) -> Action {
title = String::from("Processing"); title = String::from("Processing");
// TODO: FIXME // TODO: FIXME
} }
Mode::ScanWinImages => { Mode::ScanWinSources => {
select_type = SelectionType::Loop; select_type = SelectionType::Loop;
title = String::from("Scanning"); title = String::from("Scanning");
// TODO: FIXME // TODO: FIXME
} }
Mode::SelectWinSource => {
select_type = SelectionType::One;
title = String::from("Select Windows Source");
if let Ok(wim_sources) = app.state.wim_sources.lock() {
wim_sources
.get_file_list()
.iter()
.for_each(|wim_file| items.push(wim_file.path.clone()));
}
}
Mode::SelectWinImage => { Mode::SelectWinImage => {
select_type = SelectionType::One; select_type = SelectionType::One;
title = String::from("Select Windows Image"); title = String::from("Select Windows Image");
// TODO: FIXME, I think this whole section could be better... // TODO: FIXME
} }
Mode::SelectDisks => { Mode::SelectDisks => {
select_type = SelectionType::One; select_type = SelectionType::One;
@ -546,7 +559,65 @@ fn build_right_items(app: &App) -> Action {
.iter() .iter()
.for_each(|disk| items.push(get_disk_description_right(disk, &None))); .for_each(|disk| items.push(get_disk_description_right(disk, &None)));
} }
Mode::SelectTableType | Mode::SelectWinImage | Mode::SetUserName | Mode::Confirm => { Mode::SelectWinSource => {
// Disk Info
let type_str = match app.state.table_type.clone().unwrap() {
PartitionTableType::Guid => "GPT",
PartitionTableType::Legacy => "MBR",
};
let mut label_dv_lines = vec![
DVLine {
line_parts: vec![
String::from("Dest"),
String::from(" (WARNING: ALL DATA WILL BE DELETED!)"),
],
line_colors: vec![Color::Cyan, Color::Red],
},
DVLine {
line_parts: vec![format!(" (Will be formatted {type_str})")],
line_colors: vec![Color::Yellow],
},
DVLine::blank(),
];
let disk_list = app.state.disk_list.lock().unwrap();
if let Some(index) = app.state.disk_index_dest
&& let Some(disk) = disk_list.get(index)
{
get_disk_description_right(disk, &None)
.into_iter()
.for_each(|dv_line| label_dv_lines.push(dv_line));
}
labels.push(label_dv_lines);
// WIM Info
if let Ok(wim_sources) = app.state.wim_sources.lock() {
wim_sources.get_file_list().iter().for_each(|source| {
let mut wim_dv_lines = vec![
DVLine {
line_parts: vec![String::from("WIM Info")],
line_colors: vec![Color::Cyan],
},
DVLine {
line_parts: vec![source.path.clone()],
line_colors: vec![Color::Reset],
},
DVLine::blank(),
DVLine {
line_parts: vec![String::from("Images")],
line_colors: vec![Color::Blue],
},
];
source.images.iter().for_each(|image| {
wim_dv_lines.push(DVLine {
line_parts: vec![format!("{image}")],
line_colors: vec![Color::Reset],
})
});
items.push(wim_dv_lines);
});
}
}
Mode::SelectTableType | Mode::SetUserName | Mode::Confirm => {
// Labels // Labels
let dest_dv_line = DVLine { let dest_dv_line = DVLine {
line_parts: vec![ line_parts: vec![

View file

@ -77,7 +77,7 @@ impl Component for WimScan {
} }
fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> {
if self.mode != Mode::ScanWinImages { if self.mode != Mode::ScanWinSources {
return Ok(()); return Ok(());
} }
frame.render_widget(Clear, area); frame.render_widget(Clear, area);
@ -117,36 +117,26 @@ impl Component for WimScan {
.iter() .iter()
.map(|wimfile| ListItem::new(format!("{}\n\n", wimfile.path))), .map(|wimfile| ListItem::new(format!("{}\n\n", wimfile.path))),
); );
let left_list = List::new(left_list) let left_list = List::new(left_list).block(
.block( Block::default()
Block::default() .borders(Borders::ALL)
.borders(Borders::ALL) .padding(Padding::new(1, 1, 1, 1)),
.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_widget(left_list, left_body); frame.render_widget(left_list, left_body);
// Network // Network
let mut right_list = Vec::new(); let mut right_list = Vec::new();
right_list.extend( right_list.extend(wim_sources.network.iter().map(|wimfile| {
wim_sources ListItem::new(format!(
.network "{}\n\n",
.iter() wimfile.path.split("\\").last().unwrap_or(&wimfile.path)
.map(|wimfile| ListItem::new(format!("{}\n\n", wimfile.path))), ))
}));
let right_list = List::new(right_list).block(
Block::default()
.borders(Borders::ALL)
.padding(Padding::new(1, 1, 1, 1)),
); );
let right_list = List::new(right_list)
.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_widget(right_list, right_body); frame.render_widget(right_list, right_body);
} }

View file

@ -62,12 +62,30 @@ static WIN_BUILDS: LazyLock<HashMap<&str, &str>> = LazyLock::new(|| {
]) ])
}); });
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct WimFile { pub struct WimFile {
pub path: String, pub path: String,
pub images: Vec<WimImage>, pub images: Vec<WimImage>,
} }
impl WimFile {
pub fn summary(&self) -> String {
let mut s = format!("{self}");
self.images.iter().for_each(|image| {
let image = format!("\n\t\t{image}");
s.push_str(&image);
});
s
}
}
impl fmt::Display for WimFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.path.split("\\").last().unwrap_or(&self.path))
}
}
impl PartialEq for WimFile { impl PartialEq for WimFile {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.path == other.path self.path == other.path
@ -144,6 +162,22 @@ impl WimSources {
self.network.sort(); self.network.sort();
} }
pub fn get_file(&self, index: usize) -> WimFile {
let num_local = self.local.len();
let index = if index < num_local {
index
} else {
index - num_local
};
self.local.get(index).unwrap().clone()
}
pub fn get_file_list(&self) -> Vec<WimFile> {
let mut list = self.local.clone();
list.append(&mut self.network.clone());
list
}
pub fn reset_all(&mut self) { pub fn reset_all(&mut self) {
self.local.clear(); self.local.clear();
self.network.clear(); self.network.clear();