fix(tui): apply username folders everywhere and resume in place
Move the sanitizer next to the directory helpers so the CLI download command and the daemon honour use_username_dirs too, not only the TUI. Resumed downloads keep the folder they were saved with instead of nesting the username a second time, and toggling the setting applies to the next download without a restart. Document the config key.
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
use super::MainTui;
|
||||
use crate::directories::download_dir_for;
|
||||
use crate::models::{DownloadEntry, FileDisplayData};
|
||||
use crate::ui::panes::{InfoSubject, selected_transfer};
|
||||
use crate::ui::sanitize_path_component;
|
||||
use soulseek_rs::types::UploadStatus;
|
||||
use soulseek_rs::{DownloadStatus, types::Download};
|
||||
use std::path::Path;
|
||||
use std::{sync::mpsc, thread};
|
||||
|
||||
impl MainTui {
|
||||
@@ -209,21 +208,15 @@ impl MainTui {
|
||||
peer_upload_speed: Some(file.speed),
|
||||
peer_free_slots: Some(file.slots),
|
||||
};
|
||||
let download_dir = if use_username_dirs {
|
||||
let sanitized_username =
|
||||
sanitize_path_component(file.username.as_str());
|
||||
Path::new(download_dir.as_str())
|
||||
.join(sanitized_username.as_str())
|
||||
.display()
|
||||
.to_string()
|
||||
} else {
|
||||
download_dir.clone()
|
||||
};
|
||||
match client.download_with_metadata(
|
||||
file.filename.clone(),
|
||||
file.username.clone(),
|
||||
file.size,
|
||||
download_dir,
|
||||
download_dir_for(
|
||||
&download_dir,
|
||||
&file.username,
|
||||
use_username_dirs,
|
||||
),
|
||||
metadata,
|
||||
) {
|
||||
Ok((download, rx)) => {
|
||||
|
||||
@@ -12,13 +12,11 @@ use crate::persist::{
|
||||
snapshot::{Snapshot, restore_messages, restore_searches},
|
||||
state::{PersistedMessage, StateStore},
|
||||
};
|
||||
use crate::ui::sanitize_path_component;
|
||||
use color_eyre::Result;
|
||||
use ratatui::{
|
||||
DefaultTerminal,
|
||||
crossterm::event::{self, Event, KeyEventKind, poll},
|
||||
};
|
||||
use std::path::Path;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
pub struct MainTui {
|
||||
@@ -134,23 +132,12 @@ impl MainTui {
|
||||
} else {
|
||||
let client = self.client.clone();
|
||||
let sender = sender.clone();
|
||||
let use_username_dirs = self.use_username_dirs;
|
||||
std::thread::spawn(move || {
|
||||
let sanitized_username =
|
||||
sanitize_path_component(entry.username.as_str());
|
||||
let download_dir = if use_username_dirs {
|
||||
Path::new(entry.download_directory.as_str())
|
||||
.join(sanitized_username.as_str())
|
||||
.display()
|
||||
.to_string()
|
||||
} else {
|
||||
entry.download_directory
|
||||
};
|
||||
match client.download(
|
||||
entry.filename.clone(),
|
||||
entry.username,
|
||||
entry.size,
|
||||
download_dir,
|
||||
entry.download_directory,
|
||||
) {
|
||||
Ok((download, rx)) => {
|
||||
let _ = sender.send((download, rx));
|
||||
@@ -268,6 +255,7 @@ impl MainTui {
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments, reason = "one call site per mode")]
|
||||
pub fn launch_main_tui(
|
||||
terminal: DefaultTerminal,
|
||||
client: Arc<dyn SessionApi>,
|
||||
|
||||
@@ -109,6 +109,7 @@ impl MainTui {
|
||||
if dir_applied {
|
||||
self.download_dir.clone_from(&download_dir);
|
||||
}
|
||||
self.use_username_dirs = use_username_dirs;
|
||||
|
||||
// Persist to config.toml so the change survives a restart. What was
|
||||
// refused live is not written either: the file must not promise a
|
||||
|
||||
@@ -108,6 +108,30 @@ fn applying_settings_locally_stays_on_this_machine() {
|
||||
assert_eq!(tui.download_dir, downloads_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn toggling_username_folders_applies_live_and_persists() {
|
||||
let session = Arc::new(TalkativeSession::default());
|
||||
let scratch = tempfile::tempdir().expect("a temp dir");
|
||||
let config_path = scratch.path().join("config.toml");
|
||||
let mut tui = MainTui::new(
|
||||
session,
|
||||
scratch.path().to_str().expect("utf-8").to_string(),
|
||||
false,
|
||||
Duration::from_secs(1),
|
||||
None,
|
||||
Some(config_path.clone()),
|
||||
);
|
||||
|
||||
tui.open_settings();
|
||||
tui.state.settings.as_mut().expect("open").use_username_dirs = true;
|
||||
tui.apply_settings();
|
||||
|
||||
assert!(tui.use_username_dirs, "the next download uses it");
|
||||
let saved = crate::persist::config::FileConfig::load(&config_path)
|
||||
.expect("config saved");
|
||||
assert_eq!(saved.use_username_dirs, Some(true));
|
||||
}
|
||||
|
||||
/// The account block answers "who is this session, and what is it
|
||||
/// offering" without a trip to another screen.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user