Skip to content

Commit

Permalink
feat: torrent tab status bar (#43)
Browse files Browse the repository at this point in the history
* feat: torrent tab status bar

* chore: remove commented

* fix: compiler warnings

* feat: decrement selected torrent on delete

* feat: add/delete torrent name

* fix: warnings

* feat: cancel status bar after 5s

* fix: nits

* fix: tick nits

* fix: comments

* fix: spacing
  • Loading branch information
aidanaden authored and micielski committed Jul 4, 2024
1 parent 30aa7a1 commit f685cbf
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 32 deletions.
30 changes: 18 additions & 12 deletions rm-main/src/transmission/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,22 @@ pub async fn action_handler(ctx: app::Ctx, mut trans_rx: UnboundedReceiver<Torre
download_dir: directory,
..Default::default()
};

if let Err(e) = ctx.client.lock().await.torrent_add(args).await {
let error_title = "Failed to add a torrent";
let msg = "Failed to add torrent with URL/Path:\n\"".to_owned()
+ url
+ "\"\n"
+ &e.to_string();
let error_message = ErrorMessage {
title: error_title.to_string(),
message: msg,
};
ctx.send_action(Action::Error(Box::new(error_message)));
match ctx.client.lock().await.torrent_add(args).await {
Ok(_) => {
ctx.send_action(Action::TaskSuccess);
}
Err(e) => {
let error_title = "Failed to add a torrent";
let msg = "Failed to add torrent with URL/Path:\n\"".to_owned()
+ url
+ "\"\n"
+ &e.to_string();
let error_message = ErrorMessage {
title: error_title.to_string(),
message: msg,
};
ctx.send_action(Action::Error(Box::new(error_message)));
}
}
}
TorrentAction::Stop(ids) => {
Expand All @@ -76,6 +80,7 @@ pub async fn action_handler(ctx: app::Ctx, mut trans_rx: UnboundedReceiver<Torre
.torrent_remove(ids, true)
.await
.unwrap();
ctx.send_action(Action::TaskSuccess)
}
TorrentAction::DeleteWithoutFiles(ids) => {
ctx.client
Expand All @@ -84,6 +89,7 @@ pub async fn action_handler(ctx: app::Ctx, mut trans_rx: UnboundedReceiver<Torre
.torrent_remove(ids, false)
.await
.unwrap();
ctx.send_action(Action::TaskSuccess)
}
TorrentAction::GetTorrentInfo(id, torrent_info) => {
let new_torrent_info = ctx
Expand Down
82 changes: 69 additions & 13 deletions rm-main/src/ui/tabs/torrents/task_manager.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use std::sync::{Arc, Mutex};

use ratatui::prelude::*;
use throbber_widgets_tui::ThrobberState;

use crate::{app, ui::components::Component};
use rm_shared::action::Action;
use rm_shared::{action::Action, status_task::StatusTask};

use super::{
tasks::{
add_magnet::AddMagnetBar,
default::DefaultBar,
delete_torrent::{self, DeleteBar},
delete_torrent::{self, DeleteBar, TorrentInfo},
filter::FilterBar,
status::{CurrentTaskState, StatusBar},
},
TableManager,
};
Expand All @@ -31,11 +33,22 @@ impl TaskManager {
}
}

enum CurrentTask {
pub enum CurrentTask {
AddMagnetBar(AddMagnetBar),
DeleteBar(DeleteBar),
FilterBar(FilterBar),
Default(DefaultBar),
Status(StatusBar),
}

impl CurrentTask {
fn tick(&mut self) -> Option<Action> {
if let Self::Status(status_bar) = self {
status_bar.tick()
} else {
None
}
}
}

impl Component for TaskManager {
Expand All @@ -44,20 +57,46 @@ impl Component for TaskManager {
use Action as A;
match &mut self.current_task {
CurrentTask::AddMagnetBar(magnet_bar) => match magnet_bar.handle_actions(action) {
Some(A::Quit) => self.finish_task(),
Some(A::TaskPending(task)) => self.pending_task(task),
Some(A::Quit) => self.cancel_task(),
Some(A::Render) => Some(A::Render),
_ => None,
},

CurrentTask::DeleteBar(delete_bar) => match delete_bar.handle_actions(action) {
Some(A::Quit) => self.finish_task(),
Some(A::TaskPending(task)) => {
let selected = self
.table_manager
.lock()
.unwrap()
.table
.state
.borrow()
.selected();

// select closest existing torrent
if let Some(idx) = selected {
if idx > 0 {
self.table_manager.lock().unwrap().table.previous();
}
}
self.pending_task(task)
}
Some(A::Quit) => self.cancel_task(),
Some(A::Render) => Some(A::Render),
_ => None,
},

CurrentTask::FilterBar(filter_bar) => match filter_bar.handle_actions(action) {
Some(A::Quit) => self.finish_task(),
Some(A::Quit) => self.cancel_task(),
Some(A::Render) => Some(A::Render),
_ => None,
},

CurrentTask::Status(status_bar) => match status_bar.handle_actions(action) {
Some(A::Quit) => self.cancel_task(),
Some(A::Render) => Some(A::Render),
Some(action) => self.handle_events_to_manager(&action),
_ => None,
},

Expand All @@ -71,8 +110,13 @@ impl Component for TaskManager {
CurrentTask::DeleteBar(delete_bar) => delete_bar.render(f, rect),
CurrentTask::FilterBar(filter_bar) => filter_bar.render(f, rect),
CurrentTask::Default(default_bar) => default_bar.render(f, rect),
CurrentTask::Status(status_bar) => status_bar.render(f, rect),
}
}

fn tick(&mut self) -> Option<Action> {
self.current_task.tick()
}
}

impl TaskManager {
Expand Down Expand Up @@ -100,7 +144,10 @@ impl TaskManager {
if let Some(torrent) = self.table_manager.lock().unwrap().current_torrent() {
self.current_task = CurrentTask::DeleteBar(DeleteBar::new(
self.ctx.clone(),
vec![torrent.id.clone()],
vec![TorrentInfo {
id: torrent.id.clone(),
name: torrent.torrent_name.clone(),
}],
mode,
));
Some(Action::SwitchToInputMode)
Expand All @@ -109,12 +156,21 @@ impl TaskManager {
}
}

fn finish_task(&mut self) -> Option<Action> {
if !matches!(self.current_task, CurrentTask::Default(_)) {
self.current_task = CurrentTask::Default(DefaultBar::new(self.ctx.clone()));
Some(Action::SwitchToNormalMode)
} else {
None
fn pending_task(&mut self, task: StatusTask) -> Option<Action> {
if matches!(self.current_task, CurrentTask::Status(_)) {
return None;
}
let state = Arc::new(Mutex::new(ThrobberState::default()));
self.current_task =
CurrentTask::Status(StatusBar::new(task, CurrentTaskState::Loading(state)));
Some(Action::SwitchToNormalMode)
}

fn cancel_task(&mut self) -> Option<Action> {
if matches!(self.current_task, CurrentTask::Default(_)) {
return None;
}
self.current_task = CurrentTask::Default(DefaultBar::new(self.ctx.clone()));
Some(Action::SwitchToNormalMode)
}
}
8 changes: 5 additions & 3 deletions rm-main/src/ui/tabs/torrents/tasks/add_magnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
transmission::TorrentAction,
ui::{components::Component, tabs::torrents::input_manager::InputManager, to_input_request},
};
use rm_shared::action::Action;
use rm_shared::{action::Action, status_task::StatusTask};

pub struct AddMagnetBar {
input_magnet_mgr: InputManager,
Expand All @@ -25,7 +25,7 @@ impl AddMagnetBar {
Self {
input_magnet_mgr: InputManager::new(
ctx.clone(),
"Add (Magnet URL/ Torrent path): ".to_string(),
"Add (Magnet URL / Torrent path): ".to_string(),
),
input_location_mgr: InputManager::new_with_value(
ctx.clone(),
Expand Down Expand Up @@ -66,7 +66,9 @@ impl AddMagnetBar {
self.input_magnet_mgr.text(),
Some(self.input_location_mgr.text()),
));
return Some(Action::Quit);
return Some(Action::TaskPending(StatusTask::Add(
self.input_magnet_mgr.text(),
)));
}
if input.code == KeyCode::Esc {
return Some(Action::Quit);
Expand Down
21 changes: 17 additions & 4 deletions rm-main/src/ui/tabs/torrents/tasks/delete_torrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@ use crate::{
ui::{components::Component, tabs::torrents::input_manager::InputManager, to_input_request},
};
use rm_shared::action::Action;
use rm_shared::status_task::StatusTask;

#[derive(Clone)]
pub struct TorrentInfo {
pub id: Id,
pub name: String,
}

pub struct DeleteBar {
torrents_to_delete: Vec<Id>,
torrents_to_delete: Vec<TorrentInfo>,
ctx: app::Ctx,
input_mgr: InputManager,
mode: Mode,
Expand All @@ -22,7 +29,7 @@ pub enum Mode {
}

impl DeleteBar {
pub fn new(ctx: app::Ctx, to_delete: Vec<Id>, mode: Mode) -> Self {
pub fn new(ctx: app::Ctx, to_delete: Vec<TorrentInfo>, mode: Mode) -> Self {
let prompt = {
match mode {
Mode::WithFiles => "Really delete selected WITH files? (y/n) ".to_string(),
Expand Down Expand Up @@ -50,7 +57,11 @@ impl Component for DeleteBar {
if input.code == KeyCode::Enter {
let text = self.input_mgr.text().to_lowercase();
if text == "y" || text == "yes" {
let torrents_to_delete = self.torrents_to_delete.clone();
let torrents_to_delete: Vec<Id> = self
.torrents_to_delete
.iter()
.map(|x| x.id.clone())
.collect();
match self.mode {
Mode::WithFiles => self.ctx.send_torrent_action(
TorrentAction::DeleteWithFiles(torrents_to_delete),
Expand All @@ -62,7 +73,9 @@ impl Component for DeleteBar {
))
}
}
return Some(Action::Quit);
return Some(Action::TaskPending(StatusTask::Delete(
self.torrents_to_delete[0].name.clone(),
)));
} else if text == "n" || text == "no" {
return Some(Action::Quit);
}
Expand Down
1 change: 1 addition & 0 deletions rm-main/src/ui/tabs/torrents/tasks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pub mod add_magnet;
pub mod default;
pub mod delete_torrent;
pub mod filter;
pub mod status;
Loading

0 comments on commit f685cbf

Please sign in to comment.