mirror of
https://github.com/Xevion/factorio-achievements-fixer.git
synced 2025-12-14 10:11:41 -06:00
Humanized duration with custom formatter
This commit is contained in:
10
src-tauri/Cargo.lock
generated
10
src-tauri/Cargo.lock
generated
@@ -861,6 +861,7 @@ name = "factorio-achievements-fixer"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"human_bytes",
|
"human_bytes",
|
||||||
|
"humanize-duration",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"simple-home-dir",
|
"simple-home-dir",
|
||||||
@@ -1421,6 +1422,15 @@ version = "0.4.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91f255a4535024abf7640cb288260811fc14794f62b063652ed349f9a6c2348e"
|
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]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.5.1"
|
version = "1.5.1"
|
||||||
|
|||||||
@@ -27,4 +27,5 @@ tauri-plugin-fs = "2"
|
|||||||
simple-home-dir = "0.4.4"
|
simple-home-dir = "0.4.4"
|
||||||
human_bytes = "0.4.3"
|
human_bytes = "0.4.3"
|
||||||
time = "0.3.36"
|
time = "0.3.36"
|
||||||
|
humanize-duration = "0.0.6"
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,48 @@
|
|||||||
use human_bytes::human_bytes;
|
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 serde::Serialize;
|
||||||
use simple_home_dir::home_dir;
|
use simple_home_dir::home_dir;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::metadata;
|
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")]
|
#[cfg(target_os = "windows")]
|
||||||
fn get_save_directories() -> Vec<String> {
|
fn get_save_directories() -> Vec<String> {
|
||||||
@@ -52,17 +91,14 @@ fn get_save_directories() -> Vec<String> {
|
|||||||
save_directories
|
save_directories
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SaveFileInternal {
|
|
||||||
path: String,
|
|
||||||
last_modified: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
struct SaveFile {
|
struct SaveFile {
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
size: String,
|
size: String,
|
||||||
last_modified: String,
|
last_modified: String,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
modified_delta: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -98,6 +134,7 @@ fn find_save_files() -> Vec<SaveFile> {
|
|||||||
let save_directories = get_save_directories();
|
let save_directories = get_save_directories();
|
||||||
let mut save_files = Vec::new();
|
let mut save_files = Vec::new();
|
||||||
|
|
||||||
|
// Collect all save files
|
||||||
for dir in save_directories {
|
for dir in save_directories {
|
||||||
println!("Save directory found: {}", dir);
|
println!("Save directory found: {}", dir);
|
||||||
if let Ok(entries) = fs::read_dir(dir) {
|
if let Ok(entries) = fs::read_dir(dir) {
|
||||||
@@ -109,21 +146,46 @@ fn find_save_files() -> Vec<SaveFile> {
|
|||||||
|
|
||||||
let file_path = entry.path();
|
let file_path = entry.path();
|
||||||
if let Ok(metadata) = metadata(&file_path) {
|
if let Ok(metadata) = metadata(&file_path) {
|
||||||
let size = human_bytes(metadata.len() as f64);
|
let modified = metadata.modified();
|
||||||
let last_modified =
|
if modified.is_err() {
|
||||||
Into::<OffsetDateTime>::into(metadata.modified().unwrap())
|
continue;
|
||||||
.format(
|
}
|
||||||
&time::format_description::parse(
|
|
||||||
"[year]-[month]-[day] [hour]:[minute]:[second]",
|
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(" ", "")
|
||||||
.unwrap();
|
+ " ago"
|
||||||
|
};
|
||||||
|
|
||||||
save_files.push(SaveFile {
|
save_files.push(SaveFile {
|
||||||
name: file_name.to_string(),
|
name: file_name.to_string(),
|
||||||
|
size: human_bytes(metadata.len() as f64),
|
||||||
path: file_path.to_str().unwrap().to_string(),
|
path: file_path.to_str().unwrap().to_string(),
|
||||||
size,
|
last_modified: human_last_modified,
|
||||||
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
|
save_files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ type SaveFile = {
|
|||||||
name: string;
|
name: string;
|
||||||
path: string;
|
path: string;
|
||||||
size: string;
|
size: string;
|
||||||
|
last_modified: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SaveSelector() {
|
export default function SaveSelector() {
|
||||||
@@ -15,6 +16,7 @@ export default function SaveSelector() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// On startup, find all save files and list them for easy selection
|
// On startup, find all save files and list them for easy selection
|
||||||
invoke<SaveFile[]>("find_save_files").then((files) => {
|
invoke<SaveFile[]>("find_save_files").then((files) => {
|
||||||
|
console.log("Save Files Acquired", files);
|
||||||
setSaveFiles(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"
|
class="flex items-center justify-between p-1 hover:cursor-pointer bg-zinc-700 rounded hover:bg-zinc-600 group"
|
||||||
title={file.path}
|
title={file.path}
|
||||||
>
|
>
|
||||||
<div className="flex justify-between w-full items-center">
|
<div className="flex justify-between text-zinc-400 w-full items-center text-sm">
|
||||||
<FolderIcon class="inline w-6 h-6 shrink-0 text-zinc-400 ml-0.5 mt-0.5 mr-1.5" />
|
<FolderIcon class="inline w-6 h-6 shrink-0 ml-0.5 mt-0.5 mr-1.5" />
|
||||||
<div className="grow text-sm font-medium text-zinc-200 truncate">
|
<div className="grow font-medium text-zinc-200 truncate">
|
||||||
{file.name}
|
{file.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-zinc-400 pl-1 shrink-0">
|
<div className="pl-1 shrink-0">{file.last_modified}</div>
|
||||||
{file.size}
|
{","}
|
||||||
</div>
|
<div className="pl-1 shrink-0">{file.size}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user