// file: crates/ksp-app-config-desk/src/tw_splash.rs // version: 5 //! Tauri-window lifecycle for the Config Desk splash window. use tauri::Emitter; // rust-rules: trait-import use tauri::Manager; // rust-rules: trait-import /// Crate-internal `WINDOW_LABEL_SPLASH` constant. pub(crate) const WINDOW_LABEL_SPLASH: &str = "splash"; const SPLASH_EVENT_NAME: &str = "ksp-splash-order"; /// Resolves the required splash window or returns a typed error. pub(crate) fn require_splash_window(manager: &impl Manager) -> ksp_core_lib::Result { let window = manager.get_webview_window(WINDOW_LABEL_SPLASH); return match window { std::option::Option::Some(value) => std::result::Result::Ok(value), std::option::Option::None => std::result::Result::Err( ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_WINDOW_MISSING, "Config Desk splash window is missing") .with_context("window_label", WINDOW_LABEL_SPLASH), ), }; } /// Executes the crate-internal splash frontend ready service operation for the owning module. pub(crate) async fn splash_frontend_ready_service( app: tauri::AppHandle, invoking_window: tauri::WebviewWindow, state: &crate::AppState, ) -> ksp_core_lib::Result<()> { if invoking_window.label() != WINDOW_LABEL_SPLASH { return std::result::Result::Err( ksp_core_lib::Error::new(crate::ERROR_CODE_SPLASH_ORIGIN_INVALID, "Splash readiness may only originate from the splash window") .with_context("window_label", invoking_window.label()), ); } if !state.begin_splash_sequence() { ksp_logging_lib::trace!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, window_label = WINDOW_LABEL_SPLASH, "duplicate splash frontend readiness ignored" ); return std::result::Result::Ok(()); } let settings = state.splash_settings(); let lifecycle_started = std::time::Instant::now(); ksp_logging_lib::debug!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, window_label = WINDOW_LABEL_SPLASH, minimum_ms = settings.minimum_ms(), minimum_source = settings.minimum_source(), fade_ms = settings.fade_ms(), fade_source = settings.fade_source(), expected_backend_lifecycle_ms = settings.expected_backend_lifecycle_ms(), "splash frontend readiness accepted; starting splash to main lifecycle" ); let fade_in = emit_order( &invoking_window, crate::SplashOrderDto::new("fade_in", std::option::Option::Some("Initialisation de KSP Config Desk..."), std::option::Option::Some(settings.fade_ms())), ); if let std::result::Result::Err(error) = fade_in { return std::result::Result::Err(error); } let minimum_wait_started = std::time::Instant::now(); tokio::time::sleep(std::time::Duration::from_millis(settings.minimum_ms())).await; ksp_logging_lib::debug!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, window_label = WINDOW_LABEL_SPLASH, configured_wait_ms = settings.minimum_ms(), actual_wait_ms = minimum_wait_started.elapsed().as_secs_f64() * 1000.0, lifecycle_elapsed_ms = lifecycle_started.elapsed().as_secs_f64() * 1000.0, "splash minimum wait completed" ); let fade_out = emit_order( &invoking_window, crate::SplashOrderDto::new("fade_out", std::option::Option::Some("Initialisation terminée."), std::option::Option::Some(settings.fade_ms())), ); if let std::result::Result::Err(error) = fade_out { return std::result::Result::Err(error); } let fade_wait_started = std::time::Instant::now(); tokio::time::sleep(std::time::Duration::from_millis(u64::from(settings.fade_ms()))).await; ksp_logging_lib::debug!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, window_label = WINDOW_LABEL_SPLASH, configured_wait_ms = settings.fade_ms(), actual_wait_ms = fade_wait_started.elapsed().as_secs_f64() * 1000.0, lifecycle_elapsed_ms = lifecycle_started.elapsed().as_secs_f64() * 1000.0, "splash fade-out wait completed" ); let show_main = crate::show_main_window(&app); if let std::result::Result::Err(error) = show_main { return std::result::Result::Err(error); } let destroyed = invoking_window.destroy(); if let std::result::Result::Err(error) = destroyed { return std::result::Result::Err( ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED, "Cannot destroy Config Desk splash window") .with_context("window_label", WINDOW_LABEL_SPLASH) .with_source(error), ); } ksp_logging_lib::debug!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, window_label = WINDOW_LABEL_SPLASH, expected_backend_lifecycle_ms = settings.expected_backend_lifecycle_ms(), actual_backend_lifecycle_ms = lifecycle_started.elapsed().as_secs_f64() * 1000.0, "splash window destroyed after main activation" ); return std::result::Result::Ok(()); } fn emit_order(window: &tauri::WebviewWindow, order: crate::SplashOrderDto) -> ksp_core_lib::Result<()> { let action = order.action.clone(); let emitted = window.emit(SPLASH_EVENT_NAME, order); return match emitted { std::result::Result::Ok(()) => { ksp_logging_lib::trace!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, window_label = WINDOW_LABEL_SPLASH, action = action.as_str(), "splash order emitted" ); std::result::Result::Ok(()) }, std::result::Result::Err(error) => std::result::Result::Err( ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED, "Cannot emit Config Desk splash order") .with_context("window_label", WINDOW_LABEL_SPLASH) .with_context("action", action) .with_source(error), ), }; }