use romm_api::core::library_scan::ScanCacheInvalidate;
use romm_api::error::user_message;
use super::super::event::BackgroundAction;
use super::super::{App, AppScreen};
use super::types::{RomLoadDone, RomLoadEvent};
impl App {
fn detail_for_background_rom_mut(
&mut self,
rom_id: u64,
) -> Option<&mut crate::tui::screens::game_detail::GameDetailScreen> {
match &mut self.screen {
AppScreen::GameDetail(detail) if detail.rom.id == rom_id => Some(detail.as_mut()),
AppScreen::MetadataMatch(picker) if picker.previous.rom.id == rom_id => {
Some(picker.previous.as_mut())
}
_ => None,
}
}
pub(in crate::tui::app) fn apply_background(&mut self, action: BackgroundAction) {
match action {
BackgroundAction::LibraryMetadataRefresh(done) => {
self.apply_library_metadata_refresh(done);
}
BackgroundAction::RomLoad(done) => self.apply_rom_load_complete(done),
BackgroundAction::CollectionPrefetch(done) => {
self.apply_collection_prefetch_complete(done);
}
BackgroundAction::SearchLoad(done) => self.apply_search_load_complete(done),
BackgroundAction::CoverLoad(done) => self.apply_cover_load_complete(done),
BackgroundAction::SaveScreenshotLoad(done) => {
self.apply_save_screenshot_load_complete(done)
}
BackgroundAction::SaveList(done) => self.apply_save_list_complete(done),
BackgroundAction::AchievementLoad(done) => self.apply_achievement_load_complete(done),
BackgroundAction::SaveUpload(done) => self.apply_save_upload_complete(done),
BackgroundAction::SaveDownload(done) => self.apply_save_download_complete(done),
BackgroundAction::MetadataSearch(done) => self.apply_metadata_search_complete(done),
BackgroundAction::MetadataApply(done) => self.apply_metadata_apply_complete(done),
BackgroundAction::DeviceList(done) => self.apply_device_list_complete(done),
BackgroundAction::PlatformList(done) => self.apply_platform_list_complete(done),
BackgroundAction::SyncPushPull(done) => self.apply_sync_push_pull_complete(done),
BackgroundAction::LibraryUploadProgress { uploaded, total } => {
self.apply_library_upload_progress(uploaded, total);
}
BackgroundAction::LibraryUploadDone(result) => {
self.apply_library_upload_complete(result)
}
BackgroundAction::LibraryScanDone(result) => self.apply_library_scan_complete(result),
BackgroundAction::StartupBootstrap(done) => self.apply_startup_bootstrap(done),
BackgroundAction::DrivePrefetch => self.drive_collection_prefetch_scheduler(),
BackgroundAction::PollFooterClear => {
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
lib.poll_footer_clear();
}
}
}
}
fn apply_startup_bootstrap(&mut self, done: super::types::StartupBootstrapDone) {
use romm_api::feature_compat::{
achievements_compatibility, metadata_edit_compatibility, save_sync_compatibility,
};
if let Some(registry) = done.registry {
self.save_sync_compat = save_sync_compatibility(®istry);
self.metadata_edit_compat = metadata_edit_compatibility(®istry);
self.achievements_compat = achievements_compatibility(®istry);
}
if done.server_version.is_some() {
self.server_version = done.server_version;
}
if let Some(status) = done.update_status {
self.startup_splash = None;
if self.startup_update_prompt.is_none() {
self.startup_update_prompt = Some(super::types::StartupUpdatePrompt {
status,
updating: false,
});
}
} else if self.startup_splash.is_none()
&& self.startup_update_prompt.is_none()
&& self.server_version.is_some()
{
self.startup_splash = Some(crate::tui::screens::connected_splash::StartupSplash::new(
self.config.base_url.clone(),
self.server_version.clone(),
));
}
self.startup_bootstrap_rx = None;
}
fn apply_rom_load_complete(&mut self, done: RomLoadDone) {
if !super::super::rom_load::primary_rom_load_result_is_current(done.gen, self.rom_load_gen)
{
return;
}
let matches_selection = matches!(
&self.screen,
AppScreen::LibraryBrowse(lib)
if super::super::rom_load::primary_rom_load_result_matches_selection(lib, &done.key)
);
let on_library_screen = matches!(self.screen, AppScreen::LibraryBrowse(_));
if on_library_screen && !matches_selection {
if matches!(done.event, RomLoadEvent::Complete | RomLoadEvent::Failed(_)) {
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
lib.set_rom_loading(false);
}
}
tracing::debug!(
"rom-list-render skipped stale completion context={}",
done.context
);
return;
}
match done.event {
RomLoadEvent::Batch(roms) => {
let fetch_complete = romm_api::core::roms::rom_list_fetch_complete(&roms);
let cache_complete = romm_api::core::roms::rom_list_cache_complete(&roms);
if let Some(ref k) = done.key {
if cache_complete {
self.rom_cache
.insert(k.clone(), roms.clone(), done.expected);
self.rom_partials.remove(k);
} else if !fetch_complete {
self.rom_partials
.insert(k.clone(), (done.expected, roms.clone()));
}
}
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
if matches_selection {
lib.set_roms(roms);
}
}
tracing::debug!(
"rom-list-render batch context={} latency_ms={}",
done.context,
done.started.elapsed().as_millis()
);
}
RomLoadEvent::Failed(e) => {
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
lib.set_metadata_footer(Some(format!(
"Could not load games: {}",
user_message(&e)
)));
lib.set_rom_loading(false);
}
}
RomLoadEvent::Complete => {
if let Some(ref k) = done.key {
self.rom_partials.remove(k);
}
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
lib.set_rom_loading(false);
}
}
}
}
fn apply_collection_prefetch_complete(&mut self, done: super::types::CollectionPrefetchDone) {
self.collection_prefetch_inflight_keys.remove(&done.key);
if let Some(roms) = done.roms {
if romm_api::core::roms::rom_list_cache_complete(&roms) {
self.rom_cache.insert(done.key, roms, done.expected);
} else {
tracing::debug!(
"collection prefetch incomplete; not writing disk cache key={:?}",
done.key
);
}
} else if let Some(warning) = done.warning {
tracing::debug!("{warning}");
}
}
fn apply_search_load_complete(&mut self, done: super::types::SearchLoadDone) {
use super::types::SearchLoadEvent;
if done.gen != self.search_load_gen {
return;
}
if let AppScreen::Search(ref mut search) = self.screen {
match done.event {
SearchLoadEvent::Batch(roms) => {
search.set_results_for_query(done.query, roms);
}
SearchLoadEvent::Failed(err) => {
search.loading = false;
self.set_error(err);
}
SearchLoadEvent::Complete => {
search.loading = false;
}
}
}
}
fn apply_cover_load_complete(&mut self, done: super::types::CoverLoadDone) {
if let Some(detail) = self.detail_for_background_rom_mut(done.rom_id) {
match done.result {
Ok(image) => detail.apply_cover_image(image),
Err(err) => detail.apply_cover_error(format!(
"Cover failed: {}",
romm_api::core::utils::truncate(&user_message(&err), 120)
)),
}
}
}
fn apply_save_screenshot_load_complete(&mut self, done: super::types::SaveScreenshotLoadDone) {
if let Some(detail) = self.detail_for_background_rom_mut(done.rom_id) {
match done.result {
Ok(image) => detail.apply_save_screenshot_image(image),
Err(err) => detail.apply_save_screenshot_error(format!(
"Screenshot failed: {}",
romm_api::core::utils::truncate(&user_message(&err), 120)
)),
}
}
}
fn apply_save_list_complete(&mut self, done: super::types::SaveListDone) {
if let Some(detail) = self.detail_for_background_rom_mut(done.rom_id) {
match done.result {
Ok(rows) => detail.apply_saves(rows),
Err(e) => detail.apply_saves_error(user_message(&e)),
}
}
self.maybe_start_save_screenshot_load();
}
fn apply_achievement_load_complete(&mut self, done: super::types::AchievementLoadDone) {
use romm_api::core::achievements::AchievementLoadResult;
if done.gen != self.achievement_load_gen {
return;
}
if let Some(detail) = self.detail_for_background_rom_mut(done.rom_id) {
match done.result {
Ok(AchievementLoadResult::Loaded { rows, summary }) => {
detail.apply_achievements_loaded(rows, summary);
}
Ok(AchievementLoadResult::Empty(msg)) => detail.apply_achievements_empty(msg),
Err(e) => detail.apply_achievements_error(user_message(&e)),
}
}
}
fn apply_save_upload_complete(&mut self, done: super::types::SaveUploadDone) {
use std::time::{Duration, Instant};
let mut refresh_saves = false;
if let Some(detail) = self.detail_for_background_rom_mut(done.rom_id) {
match done.result {
Ok(()) => {
detail.message = Some("Save uploaded. Refreshing saves...".into());
detail.message_clear_at = Some(Instant::now() + Duration::from_secs(3));
refresh_saves = true;
}
Err(e) => {
detail.message = Some(format!("Save upload failed: {}", user_message(&e)));
detail.message_clear_at = Some(Instant::now() + Duration::from_secs(5));
}
}
}
if refresh_saves {
self.spawn_save_list_worker(done.rom_id);
}
}
fn apply_save_download_complete(&mut self, done: super::types::SaveDownloadDone) {
use std::time::{Duration, Instant};
let mut refresh_saves = false;
if let Some(detail) = self.detail_for_background_rom_mut(done.rom_id) {
match done.result {
Ok(path) => {
detail.message = Some(format!("Save downloaded: {}", path.display()));
detail.message_clear_at = Some(Instant::now() + Duration::from_secs(5));
refresh_saves = true;
}
Err(e) => {
detail.message = Some(format!("Save download failed: {}", user_message(&e)));
detail.message_clear_at = Some(Instant::now() + Duration::from_secs(5));
}
}
}
if refresh_saves {
self.spawn_save_list_worker(done.rom_id);
}
}
fn apply_device_list_complete(&mut self, done: super::types::DeviceListDone) {
use crate::tui::theme::MessageTone;
if let AppScreen::Settings(settings) = &mut self.screen {
match done.result {
Ok(devices) => {
settings.set_devices(devices);
settings.message = None;
}
Err(e) => {
settings.set_device_error(user_message(&e));
settings.message = Some((
format!("Device load failed: {}", user_message(&e)),
MessageTone::Error,
));
}
}
}
}
fn apply_platform_list_complete(&mut self, done: super::types::PlatformListDone) {
use crate::tui::theme::MessageTone;
if let AppScreen::Settings(settings) = &mut self.screen {
match done.result {
Ok(platforms) => {
settings.set_console_platforms(platforms);
settings.message = None;
}
Err(e) => {
settings.set_console_platform_error(user_message(&e));
settings.message = Some((
format!("Platform load failed: {}", user_message(&e)),
MessageTone::Error,
));
}
}
}
}
fn apply_sync_push_pull_complete(&mut self, done: super::types::SyncPushPullDone) {
use crate::tui::theme::MessageTone;
if let AppScreen::Settings(settings) = &mut self.screen {
settings.sync_inflight = false;
match done.result {
Ok(session) => {
settings.message = Some((
format!("Sync session #{}: {}", session.id, session.status),
MessageTone::Success,
));
}
Err(e) => {
settings.message = Some((
format!("Sync failed: {}", user_message(&e)),
MessageTone::Error,
));
}
}
}
}
fn apply_library_upload_progress(&mut self, uploaded: u64, total: u64) {
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
lib.set_metadata_footer(Some(format!(
"Uploading {} / {}…",
Self::format_upload_bytes(uploaded),
Self::format_upload_bytes(total)
)));
}
}
fn apply_library_upload_complete(
&mut self,
result: Result<super::types::LibraryUploadComplete, romm_api::error::RommError>,
) {
self.library_upload_done_rx = None;
self.library_upload_progress_rx = None;
self.library_upload_inflight = false;
match result {
Ok(done) => {
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
if done.scan_after {
lib.set_metadata_footer(Some(
"Upload complete. Starting library scan…".into(),
));
self.spawn_library_rescan_worker(ScanCacheInvalidate::Platform(
done.platform_id,
));
} else {
lib.set_metadata_footer(Some("Upload complete.".into()));
}
}
}
Err(e) => {
let message = format!("Upload failed: {}", user_message(&e));
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
lib.set_metadata_footer(Some(message));
} else {
self.set_error(e);
}
}
}
}
fn apply_library_scan_complete(&mut self, result: Result<(), romm_api::error::RommError>) {
self.library_scan_rx = None;
self.library_scan_inflight = false;
match result {
Ok(()) => self.on_library_scan_completed_success(),
Err(e) => {
self.library_scan_pending_invalidate = None;
let message = format!("Library scan failed: {}", user_message(&e));
if let AppScreen::LibraryBrowse(ref mut lib) = self.screen {
lib.set_metadata_footer(Some(message));
} else {
self.set_error(e);
}
}
}
}
}