basic single file duplication

This commit is contained in:
brxken128 2023-01-16 17:38:13 +00:00
parent 24de617b92
commit f81c1b35a8
5 changed files with 118 additions and 1 deletions

View file

@ -4,6 +4,7 @@ use crate::{
object::fs::{
decrypt::{FileDecryptorJob, FileDecryptorJobInit},
delete::{FileDeleterJob, FileDeleterJobInit},
duplicate::{FileDuplicatorJob, FileDuplicatorJobInit},
encrypt::{FileEncryptorJob, FileEncryptorJobInit},
erase::{FileEraserJob, FileEraserJobInit},
},
@ -122,6 +123,16 @@ pub(crate) fn mount() -> RouterBuilder {
library.spawn_job(Job::new(args, FileEraserJob {})).await;
invalidate_query!(library, "locations.getExplorerData");
Ok(())
})
})
.library_mutation("duplicateFiles", |t| {
t(|_, args: FileDuplicatorJobInit, library| async move {
library
.spawn_job(Job::new(args, FileDuplicatorJob {}))
.await;
invalidate_query!(library, "locations.getExplorerData");
Ok(())
})
})

View file

@ -0,0 +1,89 @@
use super::{context_menu_fs_info, FsInfo, ObjectType};
use crate::job::{JobError, JobReportUpdate, JobResult, JobState, StatefulJob, WorkerContext};
use serde::{Deserialize, Serialize};
use specta::Type;
use std::{collections::VecDeque, hash::Hash};
pub struct FileDuplicatorJob {}
#[derive(Serialize, Deserialize, Debug)]
pub struct FileDuplicatorJobState {}
#[derive(Serialize, Deserialize, Hash, Type)]
pub struct FileDuplicatorJobInit {
pub location_id: i32,
pub path_id: i32,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct FileDuplicatorJobStep {
pub fs_info: FsInfo,
}
const JOB_NAME: &str = "file_duplicator";
#[async_trait::async_trait]
impl StatefulJob for FileDuplicatorJob {
type Data = FileDuplicatorJobState;
type Init = FileDuplicatorJobInit;
type Step = FileDuplicatorJobStep;
fn name(&self) -> &'static str {
JOB_NAME
}
async fn init(&self, ctx: WorkerContext, state: &mut JobState<Self>) -> Result<(), JobError> {
let fs_info = context_menu_fs_info(
&ctx.library_ctx.db,
state.init.location_id,
state.init.path_id,
)
.await?;
state.steps = VecDeque::new();
state.steps.push_back(FileDuplicatorJobStep { fs_info });
ctx.progress(vec![JobReportUpdate::TaskCount(state.steps.len())]);
Ok(())
}
async fn execute_step(
&self,
ctx: WorkerContext,
state: &mut JobState<Self>,
) -> Result<(), JobError> {
let step = &state.steps[0];
let info = &step.fs_info;
match info.obj_type {
ObjectType::File => {
let mut output_path = info.obj_path.clone();
output_path.set_file_name(
info.obj_path
.clone()
.file_stem()
.unwrap()
.to_str()
.unwrap()
.to_string() + "-Copy" + "."
+ info
.obj_path
.extension()
.map_or_else(|| "", |x| x.to_str().unwrap()),
);
std::fs::copy(info.obj_path.clone(), output_path)
}
ObjectType::Directory => todo!(),
}?;
ctx.progress(vec![JobReportUpdate::CompletedTaskCount(
state.step_number + 1,
)]);
Ok(())
}
async fn finalize(&self, _ctx: WorkerContext, state: &mut JobState<Self>) -> JobResult {
Ok(Some(serde_json::to_value(&state.init)?))
}
}

View file

@ -9,6 +9,7 @@ use crate::{
pub mod decrypt;
pub mod delete;
pub mod duplicate;
pub mod encrypt;
pub mod erase;

View file

@ -85,6 +85,7 @@ export type Procedures = {
| { key: 'files.decryptFiles'; input: LibraryArgs<FileDecryptorJobInit>; result: null }
| { key: 'files.delete'; input: LibraryArgs<number>; result: null }
| { key: 'files.deleteFiles'; input: LibraryArgs<FileDeleterJobInit>; result: null }
| { key: 'files.duplicateFiles'; input: LibraryArgs<FileDuplicatorJobInit>; result: null }
| { key: 'files.encryptFiles'; input: LibraryArgs<FileEncryptorJobInit>; result: null }
| { key: 'files.eraseFiles'; input: LibraryArgs<FileEraserJobInit>; result: null }
| { key: 'files.setFavorite'; input: LibraryArgs<SetFavoriteArgs>; result: null }
@ -193,6 +194,11 @@ export interface FileDeleterJobInit {
path_id: number;
}
export interface FileDuplicatorJobInit {
location_id: number;
path_id: number;
}
export interface FileEncryptorJobInit {
location_id: number;
path_id: number;

View file

@ -172,6 +172,8 @@ export function FileItemContextMenu({ ...props }: FileItemContextMenuProps) {
const hasMountedKeys =
mountedUuids.data !== undefined && mountedUuids.data.length > 0 ? true : false;
const duplicateFiles = useLibraryMutation('files.duplicateFiles');
return (
<div className="relative">
<CM.ContextMenu trigger={props.children}>
@ -186,7 +188,15 @@ export function FileItemContextMenu({ ...props }: FileItemContextMenuProps) {
<CM.Separator />
<CM.Item label="Rename" />
<CM.Item label="Duplicate" keybind="⌘D" />
<CM.Item
label="Duplicate"
keybind="⌘D"
onClick={(e) => {
expStore.locationId &&
props.item.id &&
duplicateFiles.mutate({ location_id: expStore.locationId, path_id: props.item.id });
}}
/>
<CM.Separator />