mirror of
https://github.com/kristoferssolo/traxor.git
synced 2025-10-21 20:10:35 +00:00
feat: add multiple torrent select option
This commit is contained in:
parent
2a3975963c
commit
b0a8d64880
@ -14,4 +14,5 @@ pub enum Action {
|
|||||||
Move,
|
Move,
|
||||||
Delete(bool),
|
Delete(bool),
|
||||||
Rename,
|
Rename,
|
||||||
|
Select,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,6 +134,18 @@ impl<'a> App<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn select(&mut self) {
|
||||||
|
let torrent = self.selected().expect("Torrent not found");
|
||||||
|
if let Some(id) = torrent.id {
|
||||||
|
if self.torrents.selected.contains(&id) {
|
||||||
|
self.torrents.selected.remove(&id);
|
||||||
|
} else {
|
||||||
|
self.torrents.selected.insert(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.next();
|
||||||
|
}
|
||||||
|
|
||||||
fn selected(&self) -> Option<&Torrent> {
|
fn selected(&self) -> Option<&Torrent> {
|
||||||
let idx = self.state.selected()?;
|
let idx = self.state.selected()?;
|
||||||
let torrent = self.torrents.torrents.get(idx)?;
|
let torrent = self.torrents.torrents.get(idx)?;
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use std::fmt::Debug;
|
use std::{collections::HashSet, fmt::Debug};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use transmission_rpc::{
|
use transmission_rpc::{
|
||||||
types::{Id, Torrent, TorrentGetField},
|
types::{Torrent, TorrentGetField},
|
||||||
TransClient,
|
TransClient,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ pub struct Torrents {
|
|||||||
/// Constructs a new instance of [`Torrents`].
|
/// Constructs a new instance of [`Torrents`].
|
||||||
pub client: TransClient,
|
pub client: TransClient,
|
||||||
pub torrents: Vec<Torrent>,
|
pub torrents: Vec<Torrent>,
|
||||||
pub ids: Option<Vec<Id>>,
|
pub selected: HashSet<i64>, // Torrent::id
|
||||||
pub fields: Option<Vec<TorrentGetField>>,
|
pub fields: Option<Vec<TorrentGetField>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ impl Torrents {
|
|||||||
Self {
|
Self {
|
||||||
client: TransClient::new(url),
|
client: TransClient::new(url),
|
||||||
torrents: Vec::new(),
|
torrents: Vec::new(),
|
||||||
ids: None,
|
selected: HashSet::new(),
|
||||||
fields: None,
|
fields: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ impl Torrents {
|
|||||||
pub async fn update(&mut self) -> &mut Self {
|
pub async fn update(&mut self) -> &mut Self {
|
||||||
self.torrents = self
|
self.torrents = self
|
||||||
.client
|
.client
|
||||||
.torrent_get(self.fields.clone(), self.ids.clone())
|
.torrent_get(self.fields.clone(), None)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.arguments
|
.arguments
|
||||||
|
|||||||
@ -63,6 +63,7 @@ impl Wrapper for TorrentGetField {
|
|||||||
TorrentGetField::UploadedEver => String::from("Uploaded"),
|
TorrentGetField::UploadedEver => String::from("Uploaded"),
|
||||||
TorrentGetField::Wanted => String::from("Wanted"),
|
TorrentGetField::Wanted => String::from("Wanted"),
|
||||||
TorrentGetField::WebseedsSendingToUs => String::from("Webseeds Sending to Us"),
|
TorrentGetField::WebseedsSendingToUs => String::from("Webseeds Sending to Us"),
|
||||||
|
TorrentGetField::FileCount => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,6 +171,7 @@ impl Wrapper for TorrentGetField {
|
|||||||
None => String::from("N/A"),
|
None => String::from("N/A"),
|
||||||
},
|
},
|
||||||
TorrentGetField::WebseedsSendingToUs => String::from("N/A"),
|
TorrentGetField::WebseedsSendingToUs => String::from("N/A"),
|
||||||
|
TorrentGetField::FileCount => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,6 +217,7 @@ impl Wrapper for TorrentGetField {
|
|||||||
TorrentGetField::UploadedEver => 10,
|
TorrentGetField::UploadedEver => 10,
|
||||||
TorrentGetField::Wanted => 10,
|
TorrentGetField::Wanted => 10,
|
||||||
TorrentGetField::WebseedsSendingToUs => 10,
|
TorrentGetField::WebseedsSendingToUs => 10,
|
||||||
|
TorrentGetField::FileCount => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,9 +19,9 @@ pub fn get_action(key_event: KeyEvent) -> Option<Action> {
|
|||||||
KeyCode::Char('1') => Some(Action::SwitchTab(0)),
|
KeyCode::Char('1') => Some(Action::SwitchTab(0)),
|
||||||
KeyCode::Char('2') => Some(Action::SwitchTab(1)),
|
KeyCode::Char('2') => Some(Action::SwitchTab(1)),
|
||||||
KeyCode::Char('3') => Some(Action::SwitchTab(2)),
|
KeyCode::Char('3') => Some(Action::SwitchTab(2)),
|
||||||
KeyCode::Char('4') => Some(Action::SwitchTab(3)),
|
|
||||||
KeyCode::Char('t') | KeyCode::Enter | KeyCode::Menu => Some(Action::ToggleTorrent),
|
KeyCode::Char('t') | KeyCode::Enter | KeyCode::Menu => Some(Action::ToggleTorrent),
|
||||||
KeyCode::Char('a') => Some(Action::ToggleAll),
|
KeyCode::Char('a') => Some(Action::ToggleAll),
|
||||||
|
KeyCode::Char(' ') => Some(Action::Select),
|
||||||
// Other handlers you could add here.
|
// Other handlers you could add here.
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -44,6 +44,7 @@ pub async fn update(app: &mut App<'_>, action: Action) -> transmission_rpc::type
|
|||||||
Action::Move => unimplemented!(),
|
Action::Move => unimplemented!(),
|
||||||
Action::Delete(x) => app.delete(x).await?,
|
Action::Delete(x) => app.delete(x).await?,
|
||||||
Action::Rename => unimplemented!(),
|
Action::Rename => unimplemented!(),
|
||||||
|
Action::Select => app.select(),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::Constraint,
|
layout::Constraint,
|
||||||
style::{Color, Style},
|
style::{Color, Style, Styled},
|
||||||
widgets::{Block, BorderType, Borders, Row, Table},
|
widgets::{Block, BorderType, Borders, Row, Table},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -8,7 +8,9 @@ use crate::app::{utils::Wrapper, App, Tab};
|
|||||||
|
|
||||||
pub fn render_table<'a>(app: &mut App, tab: Tab) -> Table<'a> {
|
pub fn render_table<'a>(app: &mut App, tab: Tab) -> Table<'a> {
|
||||||
let fields = tab.fields();
|
let fields = tab.fields();
|
||||||
|
let selected = &app.torrents.selected.clone();
|
||||||
let torrents = &app.torrents.set_fields(None).torrents;
|
let torrents = &app.torrents.set_fields(None).torrents;
|
||||||
|
let highlight_style = Style::default().bg(Color::Magenta).fg(Color::Black);
|
||||||
|
|
||||||
let rows: Vec<Row<'_>> = torrents
|
let rows: Vec<Row<'_>> = torrents
|
||||||
.iter()
|
.iter()
|
||||||
@ -16,7 +18,14 @@ pub fn render_table<'a>(app: &mut App, tab: Tab) -> Table<'a> {
|
|||||||
Row::new(
|
Row::new(
|
||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&field| field.value(torrent.clone()))
|
.map(|&field| {
|
||||||
|
if let Some(id) = &torrent.clone().id {
|
||||||
|
if selected.contains(id) {
|
||||||
|
return field.value(torrent.clone()).set_style(highlight_style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return field.value(torrent.clone()).into();
|
||||||
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -34,6 +43,9 @@ pub fn render_table<'a>(app: &mut App, tab: Tab) -> Table<'a> {
|
|||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
.style(Style::default().fg(Color::Yellow));
|
.style(Style::default().fg(Color::Yellow));
|
||||||
|
|
||||||
|
let highlight_style = Style::default().bg(Color::Blue).fg(Color::Black);
|
||||||
|
|
||||||
Table::new(rows, widths)
|
Table::new(rows, widths)
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
@ -41,7 +53,6 @@ pub fn render_table<'a>(app: &mut App, tab: Tab) -> Table<'a> {
|
|||||||
.border_type(BorderType::Rounded),
|
.border_type(BorderType::Rounded),
|
||||||
)
|
)
|
||||||
.header(header)
|
.header(header)
|
||||||
.highlight_style(Style::default().fg(Color::Red))
|
.highlight_style(highlight_style)
|
||||||
.highlight_symbol(">> ")
|
|
||||||
.column_spacing(1)
|
.column_spacing(1)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user