Files
gpx.studio/tauri/src/commands/files.rs
T

114 lines
3.2 KiB
Rust
Raw Normal View History

2026-10-14 08:51:38 +02:00
//! Creating, loading, deleting, moving, copying and pasting files and their elements, and undoing.
2026-10-14 09:22:07 +02:00
use gpx_engine::api;
2026-10-14 08:51:38 +02:00
use tauri::ipc::{InvokeBody, Request};
use tauri::State;
use uuid::Uuid;
2026-10-14 09:22:07 +02:00
use crate::state::AppState;
2026-10-14 08:51:38 +02:00
#[tauri::command(async)]
pub fn new_file(
state: State<AppState>,
name: String,
lng: Option<f64>,
lat: Option<f64>,
ele: Option<f64>,
2026-10-14 09:22:07 +02:00
) -> api::Outcome {
state.run(move |e| api::new_file(e, &name, lng, lat, ele))
2026-10-14 08:51:38 +02:00
}
2026-10-14 09:22:07 +02:00
/// The files are in the body, one after the other, the headers `lengths` and `names` (JSON,
/// percent-encoded) telling the number of bytes and the name of each one.
2026-10-14 08:51:38 +02:00
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn load_files(state: State<AppState>, request: Request<'_>) -> api::Outcome {
2026-10-14 08:51:38 +02:00
let InvokeBody::Raw(data) = request.body() else {
2026-10-14 09:22:07 +02:00
return api::Outcome::failed("the files are missing");
2026-10-14 08:51:38 +02:00
};
let header = |key: &str| {
request
.headers()
.get(key)
.and_then(|value| value.to_str().ok())
2026-10-14 09:22:07 +02:00
.and_then(percent_decode)
2026-10-14 08:51:38 +02:00
};
let (Some(lengths), Some(names)) = (
header("lengths").and_then(|json| serde_json::from_str::<Vec<usize>>(&json).ok()),
header("names").and_then(|json| serde_json::from_str::<Vec<String>>(&json).ok()),
) else {
2026-10-14 09:22:07 +02:00
return api::Outcome::failed("the lengths or the names of the files are not valid");
2026-10-14 08:51:38 +02:00
};
2026-10-14 09:22:07 +02:00
let data = data.clone();
state.run(move |e| api::load_files(e, &data, &lengths, &names))
2026-10-14 08:51:38 +02:00
}
2026-10-14 09:22:07 +02:00
fn percent_decode(value: &str) -> Option<String> {
2026-10-14 08:51:38 +02:00
let bytes = value.as_bytes();
let mut decoded = Vec::with_capacity(bytes.len());
let mut i = 0;
while i < bytes.len() {
if bytes[i] == b'%' {
let hex = value.get(i + 1..i + 3)?;
decoded.push(u8::from_str_radix(hex, 16).ok()?);
i += 3;
} else {
decoded.push(bytes[i]);
i += 1;
}
}
String::from_utf8(decoded).ok()
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn duplicate(state: State<AppState>) -> api::Outcome {
state.run(api::duplicate)
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn delete(state: State<AppState>, whole_files: bool) -> api::Outcome {
state.run(move |e| api::delete(e, whole_files))
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn delete_all(state: State<AppState>) -> api::Outcome {
state.run(api::delete_all)
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn reorder(state: State<AppState>, file_ids: Vec<Uuid>, index: usize) -> api::Outcome {
state.run(move |e| api::reorder(e, &file_ids, index))
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn copy(state: State<AppState>) -> api::Outcome {
state.run(api::copy)
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn cut(state: State<AppState>) -> api::Outcome {
state.run(api::cut)
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn paste(state: State<AppState>) -> api::Outcome {
state.run(api::paste)
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn move_elements(
state: State<AppState>,
what: api::Selection,
to: api::MoveTarget,
) -> api::Outcome {
state.run(move |e| api::move_elements(e, what, to))
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn undo(state: State<AppState>) -> api::Outcome {
state.run(api::undo)
2026-10-14 08:51:38 +02:00
}
#[tauri::command(async)]
2026-10-14 09:22:07 +02:00
pub fn redo(state: State<AppState>) -> api::Outcome {
state.run(api::redo)
2026-10-14 08:51:38 +02:00
}