diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 7ee23d1..b4fb688 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -861,6 +861,7 @@ name = "factorio-achievements-fixer" version = "0.1.0" dependencies = [ "human_bytes", + "humanize-duration", "serde", "serde_json", "simple-home-dir", @@ -1421,6 +1422,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91f255a4535024abf7640cb288260811fc14794f62b063652ed349f9a6c2348e" +[[package]] +name = "humanize-duration" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "082247a9fa508369fe52b235aef8a8dbf931b08d223a1a9b70cd400a8a77ae9c" +dependencies = [ + "time", +] + [[package]] name = "hyper" version = "1.5.1" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ec5f532..65f4419 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -27,4 +27,5 @@ tauri-plugin-fs = "2" simple-home-dir = "0.4.4" human_bytes = "0.4.3" time = "0.3.36" +humanize-duration = "0.0.6" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index df0f88e..1a27189 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,9 +1,48 @@ use human_bytes::human_bytes; +use humanize_duration::prelude::DurationExt; +use humanize_duration::Unit; +use humanize_duration::{types::DurationParts, unit, Formatter, Truncate}; use serde::Serialize; use simple_home_dir::home_dir; use std::fs; use std::fs::metadata; -use time::OffsetDateTime; + +struct SlimFormatter; + +unit!(MyYear, "y", "y"); +unit!(MyMonth, "mon", "mon"); +unit!(MyDay, "d", "d"); +unit!(MyHour, "h", "h"); +unit!(MyMinute, "m", "m"); +unit!(MySecond, "s", "s"); +unit!(MyMillis, "ms", "ms"); +unit!(MyMicro, "mms", "mms"); +unit!(MyNano, "ns", "ns"); + +impl Formatter for SlimFormatter { + fn get(&self, truncate: Truncate) -> Box { + match truncate { + Truncate::Nano => Box::new(MyNano), + Truncate::Micro => Box::new(MyMicro), + Truncate::Millis => Box::new(MyMillis), + Truncate::Second => Box::new(MySecond), + Truncate::Minute => Box::new(MyMinute), + Truncate::Hour => Box::new(MyHour), + Truncate::Day => Box::new(MyDay), + Truncate::Month => Box::new(MyMonth), + Truncate::Year => Box::new(MyYear), + } + } + + fn format( + &self, + f: &mut std::fmt::Formatter<'_>, + parts: DurationParts, + truncate: Truncate, + ) -> std::fmt::Result { + self.format_default(f, parts, truncate) + } +} #[cfg(target_os = "windows")] fn get_save_directories() -> Vec { @@ -52,17 +91,14 @@ fn get_save_directories() -> Vec { save_directories } -struct SaveFileInternal { - path: String, - last_modified: usize, -} - #[derive(Serialize, Debug)] struct SaveFile { name: String, path: String, size: String, last_modified: String, + #[serde(skip_serializing)] + modified_delta: usize, } #[tauri::command] @@ -98,6 +134,7 @@ fn find_save_files() -> Vec { let save_directories = get_save_directories(); let mut save_files = Vec::new(); + // Collect all save files for dir in save_directories { println!("Save directory found: {}", dir); if let Ok(entries) = fs::read_dir(dir) { @@ -109,21 +146,46 @@ fn find_save_files() -> Vec { let file_path = entry.path(); if let Ok(metadata) = metadata(&file_path) { - let size = human_bytes(metadata.len() as f64); - let last_modified = - Into::::into(metadata.modified().unwrap()) - .format( - &time::format_description::parse( - "[year]-[month]-[day] [hour]:[minute]:[second]", - ) - .unwrap(), + let modified = metadata.modified(); + if modified.is_err() { + continue; + } + + let modified_elapsed = match modified.unwrap().elapsed() { + Ok(elapsed) => elapsed, + Err(_) => continue, + }; + let modified_elapsed_secs = modified_elapsed.as_secs(); + + let human_last_modified = if modified_elapsed_secs < 60 { + if modified_elapsed_secs < 10 { + "just now".to_string() + } else { + "< 1min".to_string() + } + } else { + modified_elapsed + .human_with_format( + match modified_elapsed_secs / 60 { + m if m < 60 => Truncate::Minute, + m if m < 60 * 36 => Truncate::Hour, + m if m < 60 * 24 * 31 => Truncate::Day, + m if m < 60 * 24 * 31 * 18 => Truncate::Month, + _ => Truncate::Year, + }, + SlimFormatter, ) - .unwrap(); + .to_string() + .replace(" ", "") + + " ago" + }; + save_files.push(SaveFile { name: file_name.to_string(), + size: human_bytes(metadata.len() as f64), path: file_path.to_str().unwrap().to_string(), - size, - last_modified, + last_modified: human_last_modified, + modified_delta: modified_elapsed_secs as usize, }); } } @@ -131,6 +193,9 @@ fn find_save_files() -> Vec { } } + // Sort the save files by last modified time + save_files.sort_by(|a, b| a.modified_delta.cmp(&b.modified_delta)); + save_files } diff --git a/src/views/SaveSelector.tsx b/src/views/SaveSelector.tsx index 371224a..743b994 100644 --- a/src/views/SaveSelector.tsx +++ b/src/views/SaveSelector.tsx @@ -7,6 +7,7 @@ type SaveFile = { name: string; path: string; size: string; + last_modified: string; }; export default function SaveSelector() { @@ -15,6 +16,7 @@ export default function SaveSelector() { useEffect(() => { // On startup, find all save files and list them for easy selection invoke("find_save_files").then((files) => { + console.log("Save Files Acquired", files); setSaveFiles(files); }); }, []); @@ -32,14 +34,14 @@ export default function SaveSelector() { class="flex items-center justify-between p-1 hover:cursor-pointer bg-zinc-700 rounded hover:bg-zinc-600 group" title={file.path} > -
- -
+
+ +
{file.name}
-
- {file.size} -
+
{file.last_modified}
+ {","} +
{file.size}
);