Skip to content

Commit

Permalink
feat: multiple selections (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
micielski authored Sep 6, 2024
1 parent 2844ee1 commit d75c5a0
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 77 deletions.
2 changes: 1 addition & 1 deletion rm-config/src/keymap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl<T: Into<Action> + Ord + UserAction> KeybindsHolder<T> {
}

keys.entry(&keybinding.action)
.or_insert_with(Vec::new)
.or_default()
.push(keybinding.keycode_string());
}

Expand Down
80 changes: 73 additions & 7 deletions rm-main/src/tui/tabs/torrents/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use ratatui::widgets::{Cell, Row, Table};
use rm_config::CONFIG;
use rm_shared::status_task::StatusTask;
use rustmission_torrent::RustmissionTorrent;
use transmission_rpc::types::TorrentStatus;
use tasks::TorrentSelection;
use transmission_rpc::types::{Id, TorrentStatus};

use crate::transmission;
use rm_shared::action::{Action, ErrorMessage, UpdateAction};
Expand Down Expand Up @@ -105,8 +106,21 @@ impl Component for TorrentsTab {
return ComponentAction::Nothing;
}

if !self.table_manager.selected_torrents_ids.is_empty() && action.is_soft_quit() {
self.table_manager
.table
.items
.iter_mut()
.for_each(|t| t.is_selected = false);
self.table_manager.selected_torrents_ids.drain(..);
self.task_manager.default();
self.ctx.send_action(Action::Render);
return ComponentAction::Nothing;
}

if action.is_quit() {
self.ctx.send_action(Action::HardQuit);
return ComponentAction::Nothing;
}

match action {
Expand All @@ -121,10 +135,20 @@ impl Component for TorrentsTab {
A::ShowStats => self.show_statistics_popup(),
A::ShowFiles => self.show_files_popup(),
A::Confirm => self.show_details_popup(),
A::Select => {
self.table_manager.select_current_torrent();
if !self.table_manager.selected_torrents_ids.is_empty() {
self.task_manager
.select(self.table_manager.selected_torrents_ids.len());
} else {
self.task_manager.default();
}
self.ctx.send_action(Action::Render);
}
A::Pause => self.pause_current_torrent(),
A::Delete => {
if let Some(torrent) = self.table_manager.current_torrent() {
self.task_manager.delete_torrent(torrent);
if let Some(torrent_selection) = self.get_currently_selected() {
self.task_manager.delete_torrents(torrent_selection);
}
}
A::AddMagnet => self.task_manager.add_magnet(),
Expand All @@ -136,13 +160,14 @@ impl Component for TorrentsTab {
.map(|f| f.pattern.clone()),
),
A::MoveTorrent => {
if let Some(torrent) = self.table_manager.current_torrent() {
self.task_manager.move_torrent(torrent);
if let Some(selection) = self.get_currently_selected() {
self.task_manager
.move_torrent(selection, self.ctx.session_info.download_dir.clone());
}
}
A::ChangeCategory => {
if let Some(torrent) = self.table_manager.current_torrent() {
self.task_manager.change_category(torrent);
if let Some(selection) = self.get_currently_selected() {
self.task_manager.change_category(selection);
}
}
A::XdgOpen => self.xdg_open_current_torrent(),
Expand Down Expand Up @@ -186,13 +211,34 @@ impl Component for TorrentsTab {
}
UpdateAction::UpdateTorrents(torrents) => {
let torrents = torrents.into_iter().map(RustmissionTorrent::from).collect();

self.table_manager.set_new_rows(torrents);
if self.table_manager.selected_torrents_ids.is_empty()
&& self.task_manager.is_selection_task()
{
self.task_manager.default()
}

self.bottom_stats
.update_selected_indicator(&self.table_manager);
}
UpdateAction::UpdateCurrentTorrent(_) => {
self.popup_manager.handle_update_action(action)
}
UpdateAction::CancelTorrentTask => {
if !self.task_manager.is_finished_status_task() {
return;
}

if !self.table_manager.selected_torrents_ids.is_empty() {
self.task_manager
.select(self.table_manager.selected_torrents_ids.len());
} else {
self.task_manager.default();
}
self.ctx
.send_update_action(UpdateAction::SwitchToNormalMode);
}
other => self.task_manager.handle_update_action(other),
}
}
Expand Down Expand Up @@ -279,6 +325,26 @@ impl TorrentsTab {
);
}

fn get_currently_selected(&mut self) -> Option<TorrentSelection> {
if !self.table_manager.selected_torrents_ids.is_empty() {
Some(TorrentSelection::Many(
self.table_manager
.selected_torrents_ids
.clone()
.into_iter()
.map(Id::Id)
.collect(),
))
} else if let Some(t) = self.table_manager.current_torrent() {
Some(TorrentSelection::Single(
t.id.clone(),
t.torrent_name.to_string(),
))
} else {
None
}
}

fn show_files_popup(&mut self) {
if let Some(highlighted_torrent) = self.table_manager.current_torrent() {
let popup = FilesPopup::new(self.ctx.clone(), highlighted_torrent.id.clone());
Expand Down
22 changes: 18 additions & 4 deletions rm-main/src/tui/tabs/torrents/rustmission_torrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ pub struct RustmissionTorrent {
pub uploaded_ever: String,
pub upload_ratio: String,
status: TorrentStatus,
pub style: Style,
style: Style,
pub id: Id,
pub download_dir: String,
pub activity_date: NaiveDateTime,
pub added_date: NaiveDateTime,
pub peers_connected: i64,
pub category: Option<CategoryType>,
pub error: Option<String>,
pub is_selected: bool,
}

#[derive(Clone)]
Expand All @@ -53,7 +54,7 @@ impl RustmissionTorrent {
.iter()
.map(|header| self.header_to_cell(*header))
.collect::<Row>()
.style(self.style)
.style(self.style())
.height(if self.error.is_some() { 2 } else { 1 })
}

Expand Down Expand Up @@ -162,11 +163,23 @@ impl RustmissionTorrent {
if *header == Header::Name {
cells.push(std::mem::take(&mut torrent_name_line).into())
} else {
cells.push(self.header_to_cell(*header).style(self.style))
cells.push(self.header_to_cell(*header).style(self.style()))
}
}

Row::new(cells)
if self.is_selected {
Row::new(cells).reversed()
} else {
Row::new(cells)
}
}

fn style(&self) -> Style {
if self.is_selected {
self.style.reversed()
} else {
self.style
}
}

pub fn torrent_location(&self) -> String {
Expand Down Expand Up @@ -384,6 +397,7 @@ impl From<Torrent> for RustmissionTorrent {
peers_connected,
category,
error,
is_selected: false,
}
}
}
Expand Down
50 changes: 49 additions & 1 deletion rm-main/src/tui/tabs/torrents/table_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use ratatui::{prelude::*, widgets::Row};
use rm_config::CONFIG;
use rm_shared::header::Header;
use std::{cmp::Ordering, collections::HashMap};
use transmission_rpc::types::Id;

use crate::tui::components::GenericTable;

Expand All @@ -16,6 +17,7 @@ pub struct TableManager {
pub sort_header: Option<usize>,
pub sort_reverse: bool,
pub sorting_is_being_selected: bool,
pub selected_torrents_ids: Vec<i64>,
}

pub struct Filter {
Expand All @@ -37,6 +39,7 @@ impl TableManager {
sort_header: None,
sort_reverse: false,
sorting_is_being_selected: false,
selected_torrents_ids: vec![],
}
}

Expand Down Expand Up @@ -178,6 +181,29 @@ impl TableManager {
}
}

pub fn select_current_torrent(&mut self) {
let mut is_selected = true;
if let Some(t) = self.current_torrent() {
if let Id::Id(id) = t.id {
match self.selected_torrents_ids.iter().position(|&x| x == id) {
Some(idx) => {
self.selected_torrents_ids.remove(idx);
is_selected = false;
}
None => {
self.selected_torrents_ids.push(id);
}
}
} else {
unreachable!();
}
}

if let Some(t) = self.current_torrent() {
t.is_selected = is_selected;
}
}

pub fn rows(&self) -> Vec<Row<'_>> {
if let Some(filter) = &self.filter {
let highlight_style = Style::default().fg(CONFIG.general.accent_color);
Expand Down Expand Up @@ -223,7 +249,29 @@ impl TableManager {
}
}

pub fn set_new_rows(&mut self, rows: Vec<RustmissionTorrent>) {
pub fn set_new_rows(&mut self, mut rows: Vec<RustmissionTorrent>) {
if !self.selected_torrents_ids.is_empty() {
let mut found_ids = vec![];

for row in &mut rows {
if let Id::Id(id) = row.id {
if self.selected_torrents_ids.contains(&id) {
row.is_selected = true;
found_ids.push(id);
}
}
}

let new_selected: Vec<_> = self
.selected_torrents_ids
.iter()
.cloned()
.filter(|id| found_ids.contains(id))
.collect();

self.selected_torrents_ids = new_selected;
}

self.table.set_items(rows);
self.widths = self.header_widths(&self.table.items);
self.update_rows_number();
Expand Down
Loading

0 comments on commit d75c5a0

Please sign in to comment.