Add List panel (session 9, fifteenth feature)
Renders a naming-scheme-style expression per loaded file via the same render_expression engine the Rename panel's live preview uses, fed by the same local guess_episode/guess_movie/guess_release_info matching Filter already uses. Copy List and Export to File... (a new export_text_list Tauri command - the only new backend surface this feature needed) round it out. Closes out all six original sidebar panels as real screens.
This commit is contained in:
@@ -2,6 +2,7 @@ mod cli;
|
||||
mod episodes;
|
||||
mod files;
|
||||
mod history;
|
||||
mod list;
|
||||
mod metadata;
|
||||
mod presets;
|
||||
mod settings;
|
||||
@@ -121,6 +122,7 @@ pub fn run() {
|
||||
sfv::compute_checksums,
|
||||
sfv::save_checksum_file,
|
||||
sfv::verify_checksum_file,
|
||||
list::export_text_list,
|
||||
history::list_rename_history,
|
||||
history::undo_rename_batch,
|
||||
presets::list_presets,
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//! The Tauri-facing side of the List panel: exports a set of already-rendered text
|
||||
//! lines (one per loaded file) to a plain text file the user picks via a native
|
||||
//! "Save File" dialog. This is the *only* new Tauri surface List needs - matching
|
||||
//! each file against local metadata and rendering a naming-scheme-style expression
|
||||
//! per file both reuse commands that already exist: `guess_episode`/`guess_movie`/
|
||||
//! `guess_release_info` (the same local guessers the Rename panel's "Match" and the
|
||||
//! Filter panel's scan already call) and `render_expression` (the same engine the
|
||||
//! Rename panel's live preview already calls). The frontend builds the final,
|
||||
//! newline-joined text; this module's only job is writing it to a file the user
|
||||
//! chooses, the same async native-dialog pattern `sfv::save_checksum_file` uses.
|
||||
|
||||
use tauri::AppHandle;
|
||||
use tauri_plugin_dialog::DialogExt;
|
||||
|
||||
/// The `.txt`-suffixed file name to default the Save dialog to.
|
||||
fn default_export_filename(default_name: &str) -> String {
|
||||
format!("{default_name}.txt")
|
||||
}
|
||||
|
||||
/// Opens a native "Save File" dialog defaulted to `<default_name>.txt`, and if the
|
||||
/// user doesn't cancel, writes `content` there verbatim (already newline-joined by
|
||||
/// the frontend, one rendered line per loaded file). Returns the saved path, or
|
||||
/// `None` if the user cancelled the dialog (not an error) - same shape as
|
||||
/// `sfv::save_checksum_file`.
|
||||
#[tauri::command]
|
||||
pub async fn export_text_list(app: AppHandle, default_name: String, content: String) -> Result<Option<String>, String> {
|
||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||
app.dialog()
|
||||
.file()
|
||||
.set_file_name(default_export_filename(&default_name))
|
||||
.save_file(move |result| {
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
let chosen = rx.await.map_err(|e| e.to_string())?;
|
||||
|
||||
let Some(file_path) = chosen else {
|
||||
return Ok(None);
|
||||
};
|
||||
let path = file_path.into_path().map_err(|e| e.to_string())?;
|
||||
|
||||
tauri::async_runtime::spawn_blocking({
|
||||
let path = path.clone();
|
||||
move || std::fs::write(&path, content)
|
||||
})
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(Some(path.to_string_lossy().to_string()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default_export_filename_appends_txt_extension() {
|
||||
assert_eq!(default_export_filename("my-list"), "my-list.txt");
|
||||
assert_eq!(default_export_filename(""), ".txt");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user