use std::path::PathBuf;
use redb::ReadableDatabase;
const TABLE: redb::TableDefinition<&[u8], &[u8]> = redb::TableDefinition::new("tui_prefs");
const KEY_THEME: &[u8] = b"tui_theme";
pub struct TuiStorage {
db: Option<redb::Database>,
}
impl TuiStorage {
pub fn open() -> Self {
let db = Self::db_path().and_then(|path| redb::Database::create(path).ok());
Self { db }
}
pub fn save_theme(&self, name: &str) {
if let Some(db) = &self.db {
let Ok(write_txn) = db.begin_write() else {
return;
};
{
let Ok(mut table) = write_txn.open_table(TABLE) else {
return;
};
if table.insert(KEY_THEME, name.as_bytes()).is_err() {
return;
}
}
let _ = write_txn.commit();
}
}
pub fn load_theme(&self) -> Option<String> {
let db = self.db.as_ref()?;
let read_txn = db.begin_read().ok()?;
let table = read_txn.open_table(TABLE).ok()?;
let guard = table.get(KEY_THEME).ok()??;
let bytes = guard.value();
String::from_utf8(bytes.to_vec()).ok()
}
fn db_path() -> Option<PathBuf> {
let mut path = dirs::config_dir()?;
path.push("flashkraft");
std::fs::create_dir_all(&path).ok()?;
path.push("tui-prefs.db");
Some(path)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn temp_storage() -> (TuiStorage, tempfile::TempDir) {
let tmp = tempfile::tempdir().unwrap();
let db = redb::Database::create(tmp.path().join("test.redb")).ok();
(TuiStorage { db }, tmp)
}
#[test]
fn load_theme_returns_none_when_empty() {
let (s, _tmp) = temp_storage();
assert!(s.load_theme().is_none());
}
#[test]
fn save_and_load_theme_roundtrip() {
let (s, _tmp) = temp_storage();
s.save_theme("Tokyo Night");
assert_eq!(s.load_theme().as_deref(), Some("Tokyo Night"));
}
#[test]
fn save_theme_overwrites_previous() {
let (s, _tmp) = temp_storage();
s.save_theme("Dracula");
s.save_theme("Nord");
assert_eq!(s.load_theme().as_deref(), Some("Nord"));
}
#[test]
fn load_theme_with_no_db_returns_none() {
let s = TuiStorage { db: None };
assert!(s.load_theme().is_none());
}
#[test]
fn save_theme_with_no_db_is_noop() {
let s = TuiStorage { db: None };
s.save_theme("Catppuccin Mocha"); }
#[test]
fn roundtrip_all_preset_names() {
use tui_file_explorer::Theme;
let (s, _tmp) = temp_storage();
for (name, _, _) in Theme::all_presets() {
s.save_theme(name);
assert_eq!(
s.load_theme().as_deref(),
Some(name),
"roundtrip failed for preset '{}'",
name,
);
}
}
}