Humanized duration with custom formatter

This commit is contained in:
2024-11-27 06:06:38 -06:00
parent b1af481b86
commit b5bf7c7965
4 changed files with 101 additions and 23 deletions

10
src-tauri/Cargo.lock generated
View File

@@ -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"

View File

@@ -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"

View File

@@ -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<dyn Unit> {
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<String> {
@@ -52,17 +91,14 @@ fn get_save_directories() -> Vec<String> {
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<SaveFile> {
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<SaveFile> {
let file_path = entry.path();
if let Ok(metadata) = metadata(&file_path) {
let size = human_bytes(metadata.len() as f64);
let last_modified =
Into::<OffsetDateTime>::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<SaveFile> {
}
}
// Sort the save files by last modified time
save_files.sort_by(|a, b| a.modified_delta.cmp(&b.modified_delta));
save_files
}

View File

@@ -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<SaveFile[]>("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}
>
<div className="flex justify-between w-full items-center">
<FolderIcon class="inline w-6 h-6 shrink-0 text-zinc-400 ml-0.5 mt-0.5 mr-1.5" />
<div className="grow text-sm font-medium text-zinc-200 truncate">
<div className="flex justify-between text-zinc-400 w-full items-center text-sm">
<FolderIcon class="inline w-6 h-6 shrink-0 ml-0.5 mt-0.5 mr-1.5" />
<div className="grow font-medium text-zinc-200 truncate">
{file.name}
</div>
<div className="text-sm text-zinc-400 pl-1 shrink-0">
{file.size}
</div>
<div className="pl-1 shrink-0">{file.last_modified}</div>
{","}
<div className="pl-1 shrink-0">{file.size}</div>
</div>
</div>
);