Add install driver sections

This commit is contained in:
2Shirt 2024-11-03 21:08:59 -08:00
parent c8faa283c8
commit 9414f873bd
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
7 changed files with 143 additions and 40 deletions

View file

@ -1,5 +1,14 @@
{
"keybindings": {
"InstallDrivers": {
"<Enter>": "Process",
"<Up>": "KeyUp",
"<Down>": "KeyDown",
"<q>": "Quit", // Quit the application
"<Ctrl-d>": "Quit", // Another way to quit
"<Ctrl-c>": "Quit", // Yet another way to quit
"<Ctrl-z>": "Suspend" // Suspend the application
},
"ScanDisks": {
"<q>": "Quit", // Quit the application
"<Ctrl-d>": "Quit", // Another way to quit
@ -7,6 +16,7 @@
"<Ctrl-z>": "Suspend" // Suspend the application
},
"SelectDisks": {
"<i>": "InstallDriver",
"<r>": "ScanDisks",
"<Enter>": "Process",
"<Up>": "KeyUp",

View file

@ -16,7 +16,11 @@
use serde::{Deserialize, Serialize};
use strum::Display;
use crate::{app::Mode, components::popup::Type, system::disk::Disk};
use crate::{
app::Mode,
components::popup::Type,
system::{disk::Disk, drivers::Driver},
};
#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
pub enum Action {
@ -31,6 +35,8 @@ pub enum Action {
DisplayPopup(Type, String),
Error(String),
Help,
InstallDriver,
SelectDriver(Driver),
KeyUp,
KeyDown,
SetMode(Mode),

View file

@ -41,7 +41,10 @@ use crate::{
Component,
},
config::Config,
system::disk::{get_disks, Disk},
system::{
disk::{get_disks, Disk},
drivers::{self, Driver},
},
tui::{Event, Tui},
};
@ -51,6 +54,7 @@ pub struct App {
frame_rate: f64,
components: Vec<Box<dyn Component>>,
disks: Arc<Mutex<Vec<Disk>>>,
driver: Option<Driver>,
should_quit: bool,
should_suspend: bool,
cur_mode: Mode,
@ -65,6 +69,7 @@ pub struct App {
pub enum Mode {
#[default]
ScanDisks,
InstallDrivers,
SelectDisks,
SelectParts,
Confirm,
@ -86,6 +91,7 @@ impl App {
Box::new(Popup::new()),
],
disks: Arc::new(Mutex::new(Vec::new())),
driver: None,
should_quit: false,
should_suspend: false,
config: Config::new()?,
@ -100,6 +106,7 @@ impl App {
pub fn next_mode(&mut self) -> Option<Mode> {
let new_mode = match self.cur_mode {
Mode::InstallDrivers => Mode::ScanDisks,
Mode::ScanDisks => Mode::SelectDisks,
Mode::SelectDisks | Mode::SelectParts => {
if self.selections[1].is_some() {
@ -228,6 +235,14 @@ impl App {
Action::Suspend => self.should_suspend = true,
Action::Resume => self.should_suspend = false,
Action::ClearScreen => tui.terminal.clear()?,
Action::InstallDriver => {
self.action_tx.send(Action::SetMode(Mode::InstallDrivers))?
}
Action::SelectDriver(ref driver) => {
self.driver = Some(driver.clone());
drivers::load(&driver.inf_paths);
self.action_tx.send(Action::NextScreen)?;
}
Action::Resize(w, h) => self.handle_resize(tui, w, h)?,
Action::Render => self.render(tui)?,
Action::PrevScreen => {

View file

@ -57,14 +57,15 @@ impl Component for Footer {
}
Action::SetMode(new_mode) => {
self.footer_text = match new_mode {
Mode::ScanDisks => String::from("(q) to quit"),
Mode::SelectDisks => String::from(
"(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit",
),
Mode::Confirm => {
String::from("(Enter) to confirm / (b) to go back / (q) to quit")
}
Mode::Done => String::from("(Enter) or (q) to quit"),
Mode::InstallDrivers => String::from("(Enter) to select / (q) to quit"),
Mode::ScanDisks => String::from("(q) to quit"),
Mode::SelectDisks => String::from(
"(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit",
),
_ => String::from("(Enter) to select / (b) to go back / (q) to quit"),
}
}

View file

@ -18,15 +18,25 @@ use crossterm::event::KeyEvent;
use ratatui::{prelude::*, widgets::*};
use tokio::sync::mpsc::UnboundedSender;
use super::{state::StatefulList, Component};
use crate::{action::Action, app::Mode, config::Config, system::disk::Disk};
use super::{popup::Type, state::StatefulList, Component};
use crate::{
action::Action,
app::Mode,
config::Config,
system::{
disk::{Disk, Partition},
drivers::{self, Driver},
},
};
#[derive(Default)]
pub struct Left {
command_tx: Option<UnboundedSender<Action>>,
config: Config,
title_text: String,
item_list: StatefulList<Disk>,
list_disks: StatefulList<Disk>,
list_drivers: StatefulList<Driver>,
list_parts: StatefulList<Partition>,
mode: Mode,
selections: Vec<Option<usize>>,
}
@ -66,16 +76,23 @@ impl Component for Left {
Action::Render => {
// add any logic here that should run on every render
}
Action::KeyUp => self.item_list.previous(),
Action::KeyDown => self.item_list.next(),
Action::KeyUp => self.list_disks.previous(),
Action::KeyDown => self.list_disks.next(),
Action::Process => match self.mode {
Mode::Confirm => {
if let Some(command_tx) = self.command_tx.clone() {
command_tx.send(Action::NextScreen)?;
}
}
Mode::SelectDisks | Mode::SelectParts => {
if let Some(index) = self.item_list.state.selected() {
Mode::InstallDrivers | Mode::SelectDisks | Mode::SelectParts => {
let selection: Option<usize>;
match self.mode {
Mode::InstallDrivers => selection = self.list_drivers.state.selected(),
Mode::SelectDisks => selection = self.list_disks.state.selected(),
Mode::SelectParts => selection = self.list_parts.state.selected(),
_ => panic!("This shouldn't happen!"),
}
if let Some(index) = selection {
if let Some(command_tx) = self.command_tx.clone() {
let mut selection_one: Option<usize> = None;
let mut selection_two: Option<usize> = None;
@ -95,24 +112,26 @@ impl Component for Left {
}
}
// Send selection(s)
// Send selection(s) if needed
// NOTE: This is needed to keep the app and all components in sync
match self.mode {
Mode::SelectDisks => {
command_tx
.send(Action::Select(selection_one, selection_two))?;
Mode::InstallDrivers => {
// Only need to select one entry
if let Some(driver) = self.list_drivers.pop_selected() {
command_tx.send(Action::SelectDriver(driver.clone()))?;
}
}
Mode::SelectParts => {
Mode::SelectDisks | Mode::SelectParts => {
command_tx
.send(Action::Select(selection_one, selection_two))?;
// Advance screen if both selections made
if selection_two.is_some() {
command_tx.send(Action::NextScreen)?;
}
}
_ => {}
};
// Advance screen if both selections made
if selection_two.is_some() {
command_tx.send(Action::NextScreen)?;
}
}
}
}
@ -123,9 +142,23 @@ impl Component for Left {
let prev_mode = self.mode;
self.mode = new_mode;
match new_mode {
Mode::InstallDrivers => {
self.list_drivers.set_items(drivers::scan());
self.selections[0] = None;
self.selections[1] = None;
self.title_text = String::from("Install Drivers");
if self.list_drivers.items.is_empty() {
if let Some(command_tx) = self.command_tx.clone() {
command_tx.send(Action::DisplayPopup(
Type::Error,
String::from("No drivers available to install"),
))?;
}
}
}
Mode::ScanDisks => {
self.list_disks.clear_items();
self.title_text = String::from("");
self.item_list.clear_items();
}
Mode::SelectDisks => {
self.selections[0] = None;
@ -151,7 +184,7 @@ impl Component for Left {
Mode::Done => self.title_text = String::from("Done"),
}
}
Action::UpdateDiskList(disks) => self.item_list.set_items(disks),
Action::UpdateDiskList(disks) => self.list_disks.set_items(disks),
_ => {}
}
Ok(None)
@ -170,7 +203,7 @@ impl Component for Left {
frame.render_widget(title, title_area);
// Body (scan disks)
if self.item_list.items.is_empty() {
if self.list_disks.items.is_empty() {
let paragraph = Paragraph::new(String::new()).block(
Block::default()
.borders(Borders::ALL)
@ -198,8 +231,29 @@ impl Component for Left {
// Body (list)
let mut list_items = Vec::<ListItem>::new();
if !self.item_list.items.is_empty() {
for (index, item) in self.item_list.items.iter().enumerate() {
let list_items_strings: Vec<String> = match self.mode {
Mode::InstallDrivers => self
.list_drivers
.items
.iter()
.map(|i| format!("{i}"))
.collect(),
Mode::SelectDisks => self
.list_disks
.items
.iter()
.map(|i| format!("{i}"))
.collect(),
Mode::SelectParts => self
.list_parts
.items
.iter()
.map(|i| format!("{i}"))
.collect(),
_ => panic!("This shouldn't happen."),
};
if !list_items_strings.is_empty() {
for (index, item) in list_items_strings.iter().enumerate() {
let mut item_style = Style::default();
let mut item_text_tail = "";
if let Some(selection_one) = self.selections[0] {
@ -223,7 +277,7 @@ impl Component for Left {
.highlight_style(Style::new().green().bold())
.highlight_symbol(" --> ")
.repeat_highlight_symbol(false);
frame.render_stateful_widget(list, body_area, &mut self.item_list.state);
frame.render_stateful_widget(list, body_area, &mut self.list_disks.state);
// Done
Ok(())

View file

@ -34,6 +34,7 @@ pub enum Type {
pub struct Popup {
command_tx: Option<UnboundedSender<Action>>,
config: Config,
mode: Mode,
popup_type: Type,
popup_text: String,
}
@ -71,7 +72,20 @@ impl Component for Popup {
self.popup_type = new_type;
self.popup_text = String::from(new_text);
}
Action::SetMode(Mode::ScanDisks) => self.popup_text = String::from("Scanning Disks..."),
Action::Process => {
if !self.popup_text.is_empty() && self.mode == Mode::InstallDrivers {
self.popup_text = String::from("");
if let Some(command_tx) = self.command_tx.clone() {
command_tx.send(Action::NextScreen)?;
}
}
}
Action::SetMode(mode) => {
if mode == Mode::ScanDisks {
self.popup_text = String::from("Scanning Disks...");
}
self.mode = mode;
}
_ => {}
}
Ok(None)

View file

@ -15,10 +15,11 @@
//
use std::{env, fmt, fs::read_dir, path::PathBuf, process::Command};
use serde::{Deserialize, Serialize};
use tracing::info;
use walkdir::WalkDir;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Driver {
pub name: String,
pub path: PathBuf,
@ -51,15 +52,17 @@ impl fmt::Display for Driver {
///
/// Will panic if a driver fails to load
pub fn load(inf_paths: &Vec<PathBuf>) {
// Load drivers into live environment
for inf in inf_paths {
let inf = inf.clone();
if let Ok(path) = inf.into_os_string().into_string() {
info!("Installing driver: {}", &path);
Command::new("drvload")
.arg(path)
.output()
.expect("Failed to load driver");
if cfg!(windows) {
// Load drivers into live environment
for inf in inf_paths {
let inf = inf.clone();
if let Ok(path) = inf.into_os_string().into_string() {
info!("Installing driver: {}", &path);
Command::new("drvload")
.arg(path)
.output()
.expect("Failed to load driver");
}
}
}
}