Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions romm-tui/src/tui/app/handlers/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ impl App {
fn persist_settings_screen(&mut self) -> bool {
use romm_api::config::persist_user_config;

if self.config_reset_pending_restart {
if let AppScreen::Settings(s) = &mut self.screen {
s.message = Some((
"Settings were reset. Restart romm-cli before saving again.".to_string(),
MessageTone::Warning,
));
}
return false;
}

let settings = match &self.screen {
AppScreen::Settings(s) => s,
_ => return false,
Expand Down Expand Up @@ -271,11 +281,21 @@ impl App {
match key.code {
KeyCode::Enter => match settings.confirm.take().unwrap() {
crate::tui::screens::settings::SettingsConfirm::Reset => {
let _ = romm_api::config::reset_all_settings();
settings.message = Some((
"Settings deleted. Please restart romm-cli.".to_string(),
MessageTone::Warning,
));
match romm_api::config::reset_all_settings() {
Ok(()) => {
self.config_reset_pending_restart = true;
settings.message = Some((
"Settings deleted. Please restart romm-cli.".to_string(),
MessageTone::Warning,
));
}
Err(e) => {
settings.message = Some((
format!("Failed to reset settings: {e}"),
MessageTone::Error,
));
}
}
}
crate::tui::screens::settings::SettingsConfirm::ClearCache => {
match romm_api::core::cache::RomCache::clear_file() {
Expand Down
5 changes: 5 additions & 0 deletions romm-tui/src/tui/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub struct App {
pub screen: AppScreen,
client: RommClient,
config: Config,
config_reset_pending_restart: bool,
/// RomM server version from `GET /api/heartbeat` (`SYSTEM.VERSION`), if available.
server_version: Option<String>,
save_sync_compat: SaveSyncCompatibility,
Expand Down Expand Up @@ -258,6 +259,7 @@ impl App {
))),
client,
config,
config_reset_pending_restart: false,
server_version,
save_sync_compat,
metadata_edit_compat,
Expand Down Expand Up @@ -338,6 +340,9 @@ impl App {
}

pub(in crate::tui::app) fn persist_tui_layout(&self) {
if self.config_reset_pending_restart {
return;
}
let mut config = self.config.clone();
config.auth = auth_for_persist_merge(config.auth);
if let Err(e) = romm_api::config::persist_user_config(&config) {
Expand Down
68 changes: 67 additions & 1 deletion romm-tui/src/tui/app/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use romm_api::types::{Platform, RomList};
use romm_api::update::UpdateStatus;
use serde_json::json;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, MutexGuard};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use wiremock::matchers::{method, path, query_param};
Expand Down Expand Up @@ -1748,6 +1748,34 @@ fn app_on_library() -> App {
)
}

struct IsolatedConfigDir {
_guard: MutexGuard<'static, ()>,
dir: PathBuf,
}

impl IsolatedConfigDir {
fn new(prefix: &str) -> Self {
let guard = romm_api::config::test_env_lock()
.lock()
.unwrap_or_else(|e| e.into_inner());
let ts = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let dir = std::env::temp_dir().join(format!("romm-tui-{prefix}-test-{ts}"));
std::fs::create_dir_all(&dir).unwrap();
std::env::set_var("ROMM_TEST_CONFIG_DIR", &dir);
Self { _guard: guard, dir }
}
}

impl Drop for IsolatedConfigDir {
fn drop(&mut self) {
std::env::remove_var("ROMM_TEST_CONFIG_DIR");
let _ = std::fs::remove_dir_all(&self.dir);
}
}

#[tokio::test]
async fn settings_theme_preview_reverts_when_leaving_without_save() {
std::env::remove_var("NO_COLOR");
Expand Down Expand Up @@ -1778,6 +1806,44 @@ async fn settings_theme_preview_reverts_when_leaving_without_save() {
assert_eq!(app.theme_id(), saved_theme);
}

#[tokio::test]
async fn settings_reset_prevents_later_config_persistence() {
let _env = IsolatedConfigDir::new("settings-reset");
let mut app = app_on_library();

romm_api::config::persist_user_config(&app.config).expect("seed config");
let config_path = romm_api::config::user_config_json_path().expect("config path");
assert!(config_path.exists(), "test setup should create config.json");

app.screen = AppScreen::Settings(Box::new(SettingsScreen::new(
&app.config,
None,
supported_save_sync_compatibility(),
)));
if let AppScreen::Settings(settings) = &mut app.screen {
settings.confirm = Some(SettingsConfirm::Reset);
}

app.handle_key_event(&KeyEvent::new(KeyCode::Enter, KeyModifiers::empty()))
.await
.expect("confirm reset");
assert!(!config_path.exists(), "reset should remove config.json");

app.handle_key_event(&KeyEvent::new(KeyCode::Char('S'), KeyModifiers::empty()))
.await
.expect("save after reset");
assert!(
!config_path.exists(),
"settings save must not recreate config.json after reset"
);

app.persist_tui_layout();
assert!(
!config_path.exists(),
"layout persistence must not recreate config.json after reset"
);
}

#[tokio::test]
async fn global_slash_toggles_search_overlay() {
let mut app = app_on_library();
Expand Down
Loading