From 8edd12f0b43c1bc65fc1d14407b99b56a49afe55 Mon Sep 17 00:00:00 2001 From: JEEVITHA KANNAN K S Date: Tue, 1 Oct 2024 20:36:33 +0530 Subject: [PATCH] Add per cmd multi-selection --- core/src/inner.rs | 56 +++++++++++++--------------- core/src/lib.rs | 2 +- core/tabs/system-setup/tab_data.toml | 4 +- core/tabs/utils/tab_data.toml | 5 ++- tui/src/state.rs | 44 ++++++++++------------ 5 files changed, 52 insertions(+), 59 deletions(-) diff --git a/core/src/inner.rs b/core/src/inner.rs index 6cd4356b9..96ffc6342 100644 --- a/core/src/inner.rs +++ b/core/src/inner.rs @@ -28,30 +28,18 @@ pub fn get_tabs(validate: bool) -> Vec { }); let tabs: Vec = tabs - .map( - |( - TabEntry { - name, - data, - multi_selectable, - }, - directory, - )| { - let mut tree = Tree::new(Rc::new(ListNode { - name: "root".to_string(), - description: String::new(), - command: Command::None, - task_list: String::new(), - })); - let mut root = tree.root_mut(); - create_directory(data, &mut root, &directory, validate); - Tab { - name, - tree, - multi_selectable, - } - }, - ) + .map(|(TabEntry { name, data }, directory)| { + let mut tree = Tree::new(Rc::new(ListNode { + name: "root".to_string(), + description: String::new(), + command: Command::None, + task_list: String::new(), + multi_select: false, + })); + let mut root = tree.root_mut(); + create_directory(data, &mut root, &directory, validate, true); + Tab { name, tree } + }) .collect(); if tabs.is_empty() { @@ -69,12 +57,6 @@ struct TabList { struct TabEntry { name: String, data: Vec, - #[serde(default = "default_multi_selectable")] - multi_selectable: bool, -} - -fn default_multi_selectable() -> bool { - true } #[derive(Deserialize)] @@ -89,6 +71,12 @@ struct Entry { entry_type: EntryType, #[serde(default)] task_list: String, + #[serde(default = "default_true")] + multi_select: bool, +} + +fn default_true() -> bool { + true } #[derive(Deserialize)] @@ -169,8 +157,11 @@ fn create_directory( node: &mut NodeMut>, command_dir: &Path, validate: bool, + parent_multi_select: bool, ) { for entry in data { + let multi_select = parent_multi_select && entry.multi_select; + match entry.entry_type { EntryType::Entries(entries) => { let mut node = node.append(Rc::new(ListNode { @@ -178,8 +169,9 @@ fn create_directory( description: entry.description, command: Command::None, task_list: String::new(), + multi_select, })); - create_directory(entries, &mut node, command_dir, validate); + create_directory(entries, &mut node, command_dir, validate, multi_select); } EntryType::Command(command) => { node.append(Rc::new(ListNode { @@ -187,6 +179,7 @@ fn create_directory( description: entry.description, command: Command::Raw(command), task_list: String::new(), + multi_select, })); } EntryType::Script(script) => { @@ -205,6 +198,7 @@ fn create_directory( file: script, }, task_list: entry.task_list, + multi_select, })); } } diff --git a/core/src/lib.rs b/core/src/lib.rs index b7cd631e7..4e795dd34 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -23,7 +23,6 @@ pub enum Command { pub struct Tab { pub name: String, pub tree: Tree>, - pub multi_selectable: bool, } #[derive(Clone, Hash, Eq, PartialEq)] @@ -32,4 +31,5 @@ pub struct ListNode { pub description: String, pub command: Command, pub task_list: String, + pub multi_select: bool, } diff --git a/core/tabs/system-setup/tab_data.toml b/core/tabs/system-setup/tab_data.toml index 080c06d99..af9a27965 100644 --- a/core/tabs/system-setup/tab_data.toml +++ b/core/tabs/system-setup/tab_data.toml @@ -1,5 +1,4 @@ name = "System Setup" -multi_selectable = false [[data]] name = "Arch Linux" @@ -14,6 +13,7 @@ name = "Arch Server Setup" description = "This command installs a minimal arch server setup under 5 minutes." script = "arch/server-setup.sh" task_list = "SI D" +multi_select = false [[data.entries]] name = "Paru AUR Helper" @@ -76,12 +76,14 @@ name = "Full System Cleanup" description = "This script is designed to remove unnecessary packages, clean old cache files, remove temporary files, and to empty the trash." script = "system-cleanup.sh" task_list = "RP PFM" +multi_select = false [[data]] name = "Full System Update" description = "This command updates your system to the latest packages available for your distro" script = "system-update.sh" task_list = "PFM" +multi_select = false [[data]] name = "Gaming Dependencies" diff --git a/core/tabs/utils/tab_data.toml b/core/tabs/utils/tab_data.toml index 7cfc3ed78..c67d5046f 100644 --- a/core/tabs/utils/tab_data.toml +++ b/core/tabs/utils/tab_data.toml @@ -1,8 +1,8 @@ name = "Utilities" -multi_selectable = false [[data]] name = "Monitor Control" +multi_select = false [[data.preconditions]] matches = true @@ -72,6 +72,7 @@ script = "monitor-control/set_primary_monitor.sh" [[data]] name = "User Account Manager" +multi_select = false [[data.entries]] name = "Add User" @@ -98,6 +99,7 @@ name = "Auto Mount Drive" description = "This utility is designed to help with automating the process of mounting a drive on to your system." script = "auto-mount.sh" task_list = "PFM" +multi_select = false [[data]] name = "Auto Login" @@ -114,6 +116,7 @@ name = "Bluetooth Manager" description = "This utility is designed to manage bluetooth in your system" script = "bluetooth-control.sh" task_list = "I SS" +multi_select = false [[data]] name = "Bootable USB Creator" diff --git a/tui/src/state.rs b/tui/src/state.rs index ce7248685..a7ec0bb5c 100644 --- a/tui/src/state.rs +++ b/tui/src/state.rs @@ -140,12 +140,10 @@ impl AppState { hints.push(Shortcut::new("Select item below", ["j", "Down"])); hints.push(Shortcut::new("Next theme", ["t"])); hints.push(Shortcut::new("Previous theme", ["T"])); - - if self.is_current_tab_multi_selectable() { - hints.push(Shortcut::new("Toggle multi-selection mode", ["v"])); + hints.push(Shortcut::new("Multi-selection mode", ["v"])); + if self.multi_select { hints.push(Shortcut::new("Select multiple commands", ["Space"])); } - hints.push(Shortcut::new("Next tab", ["Tab"])); hints.push(Shortcut::new("Previous tab", ["Shift-Tab"])); hints.push(Shortcut::new("Important actions guide", ["g"])); @@ -462,6 +460,13 @@ impl AppState { // enabled, need to clear it to prevent state corruption if !self.multi_select { self.selected_commands.clear() + } else { + // Prevents non multi_selectable cmd from being pushed into the selected list + if let Some(node) = self.get_selected_node() { + if !node.multi_select { + self.selected_commands.retain(|cmd| cmd.name != node.name); + } + } } } ConfirmStatus::Confirm => self.handle_confirm_command(), @@ -519,41 +524,30 @@ impl AppState { } fn toggle_multi_select(&mut self) { - if self.is_current_tab_multi_selectable() { - self.multi_select = !self.multi_select; - if !self.multi_select { - self.selected_commands.clear(); - } + self.multi_select = !self.multi_select; + if !self.multi_select { + self.selected_commands.clear(); } } fn toggle_selection(&mut self) { - if let Some(command) = self.get_selected_node() { - if self.selected_commands.contains(&command) { - self.selected_commands.retain(|c| c != &command); - } else { - self.selected_commands.push(command); + if let Some(node) = self.get_selected_node() { + if node.multi_select { + if self.selected_commands.contains(&node) { + self.selected_commands.retain(|c| c != &node); + } else { + self.selected_commands.push(node); + } } } } - pub fn is_current_tab_multi_selectable(&self) -> bool { - let index = self.current_tab.selected().unwrap_or(0); - self.tabs - .get(index) - .map_or(false, |tab| tab.multi_selectable) - } - fn update_items(&mut self) { self.filter.update_items( &self.tabs, self.current_tab.selected().unwrap(), *self.visit_stack.last().unwrap(), ); - if !self.is_current_tab_multi_selectable() { - self.multi_select = false; - self.selected_commands.clear(); - } } /// Checks either the current tree node is the root node (can we go up the tree or no)