use std::path::Path;
use std::time::UNIX_EPOCH;
use crate::date::{DateTime, local_offset_minutes};
pub(super) const PAGE: usize = 200;
const UNITS: [&str; 5] = ["B", "kB", "MB", "GB", "TB"];
const WHOLE: f64 = 10.0;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FileDetails {
pub size: u64,
pub modified: Option<i64>,
pub mode: Option<u32>,
pub readonly: bool,
}
impl FileDetails {
#[must_use]
pub fn read(path: &Path) -> Option<Self> {
let data = std::fs::symlink_metadata(path).ok()?;
let modified = data
.modified()
.ok()
.and_then(|time| time.duration_since(UNIX_EPOCH).ok())
.and_then(|since| i64::try_from(since.as_secs()).ok());
Some(Self { size: data.len(), modified, mode: mode_of(&data), readonly: data.permissions().readonly() })
}
#[must_use]
pub fn size_text(&self, folder: bool) -> String {
if folder {
return String::new();
}
let mut size = self.size as f64;
let mut unit = 0;
while size >= 1000.0 && unit + 1 < UNITS.len() {
size /= 1000.0;
unit += 1;
}
let number =
if unit == 0 || size >= WHOLE { format!("{}", size.round() as u64) } else { crate::i18n::number(size, 1) };
crate::t!("quvyta.file-manager.size", n = number.as_str(), unit = UNITS[unit])
}
#[must_use]
pub fn modified_text(&self) -> String {
let Some(seconds) = self.modified else { return String::new() };
let moment = DateTime::from_unix(seconds, local_offset_minutes());
let (date, time) = (moment.date, moment.time);
format!("{date} {:02}:{:02}", time.hour, time.minute)
}
#[must_use]
pub fn permissions_text(&self, folder: bool) -> String {
let Some(mode) = self.mode else {
let key =
if self.readonly { "quvyta.file-manager.read-only" } else { "quvyta.file-manager.read-and-write" };
return crate::t!(key);
};
let kind = if folder { 'd' } else { '-' };
let letters = ['r', 'w', 'x'];
let mut text = String::with_capacity(10);
text.push(kind);
for group in 0..3 {
for (bit, letter) in letters.iter().enumerate() {
let shift = (2 - group) * 3 + (2 - bit);
if mode & (1 << shift) == 0 {
text.push('-');
} else {
text.push(*letter);
}
}
}
text
}
}
#[cfg(unix)]
fn mode_of(data: &std::fs::Metadata) -> Option<u32> {
use std::os::unix::fs::PermissionsExt;
Some(data.permissions().mode())
}
#[cfg(not(unix))]
fn mode_of(_data: &std::fs::Metadata) -> Option<u32> {
None
}