refined cursor broadcast system and added splash
This commit is contained in:
@@ -1,7 +1,12 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
use tokio::time::{sleep, Instant};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
services::{auth::get_tokens, scene::open_scene_window},
|
services::{
|
||||||
|
auth::get_tokens,
|
||||||
|
scene::{close_splash_window, open_scene_window, open_splash_window},
|
||||||
|
},
|
||||||
state::init_app_data,
|
state::init_app_data,
|
||||||
system_tray::init_system_tray,
|
system_tray::init_system_tray,
|
||||||
};
|
};
|
||||||
@@ -12,8 +17,32 @@ pub async fn start_fdoll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn construct_app() {
|
async fn construct_app() {
|
||||||
|
open_splash_window();
|
||||||
|
|
||||||
|
// Record start time for minimum splash duration
|
||||||
|
let start = Instant::now();
|
||||||
|
|
||||||
|
// Spawn initialization tasks in parallel
|
||||||
|
// We want to wait for them to finish, but they run concurrently
|
||||||
|
let init_data = tauri::async_runtime::spawn(async {
|
||||||
init_app_data().await;
|
init_app_data().await;
|
||||||
|
});
|
||||||
|
|
||||||
|
let init_ws = tauri::async_runtime::spawn(async {
|
||||||
crate::services::ws::init_ws_client().await;
|
crate::services::ws::init_ws_client().await;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for both to complete
|
||||||
|
let _ = tokio::join!(init_data, init_ws);
|
||||||
|
|
||||||
|
// Ensure splash stays visible for at least 3 seconds
|
||||||
|
let elapsed = start.elapsed();
|
||||||
|
if elapsed < Duration::from_secs(3) {
|
||||||
|
sleep(Duration::from_secs(3) - elapsed).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close splash and open main scene
|
||||||
|
close_splash_window();
|
||||||
open_scene_window();
|
open_scene_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,15 +46,6 @@ fn setup_fdoll() -> Result<(), tauri::Error> {
|
|||||||
let file_appender = tracing_appender::rolling::daily(&app_log_dir, "friendolls.log");
|
let file_appender = tracing_appender::rolling::daily(&app_log_dir, "friendolls.log");
|
||||||
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
|
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
|
||||||
|
|
||||||
// Keep the guard alive?
|
|
||||||
// Actually `_guard` will be dropped here, which might stop logging.
|
|
||||||
// Ideally we should store the guard in the app state or use a global lazy_static if we want it to persist.
|
|
||||||
// However, `tracing_appender` docs say: "WorkerGuard should be assigned in the main function or whatever the entrypoint of the program is."
|
|
||||||
// Since we are inside `setup_fdoll` which is called from `setup`, we might lose logs if we drop it.
|
|
||||||
// But for simplicity in this context, we can just let it leak or store it in a static.
|
|
||||||
// Let's leak it for now as this is a long-running app.
|
|
||||||
Box::leak(Box::new(_guard));
|
|
||||||
|
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_target(false)
|
.with_target(false)
|
||||||
.with_thread_ids(false)
|
.with_thread_ids(false)
|
||||||
@@ -63,7 +54,7 @@ fn setup_fdoll() -> Result<(), tauri::Error> {
|
|||||||
.with_writer(non_blocking) // Log to file
|
.with_writer(non_blocking) // Log to file
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
state::init_fdoll_state();
|
state::init_fdoll_state(Some(_guard));
|
||||||
async_runtime::spawn(async move { app::start_fdoll().await });
|
async_runtime::spawn(async move { app::start_fdoll().await });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,8 +116,6 @@ async fn init_cursor_tracking() -> Result<(), String> {
|
|||||||
|
|
||||||
// The producer closure moves `tx` into it.
|
// The producer closure moves `tx` into it.
|
||||||
// device_query runs this closure on its own thread.
|
// device_query runs this closure on its own thread.
|
||||||
// Explicitly clone tx to ensure clear capture semantics
|
|
||||||
let tx_clone = tx.clone();
|
|
||||||
let _guard = device_state.on_mouse_move(move |position: &(i32, i32)| {
|
let _guard = device_state.on_mouse_move(move |position: &(i32, i32)| {
|
||||||
// `device_query` crate appears to behave
|
// `device_query` crate appears to behave
|
||||||
// differently on Windows vs other platforms.
|
// differently on Windows vs other platforms.
|
||||||
@@ -144,7 +142,7 @@ async fn init_cursor_tracking() -> Result<(), String> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send to consumer channel (non-blocking)
|
// Send to consumer channel (non-blocking)
|
||||||
if let Err(e) = tx_clone.try_send(positions) {
|
if let Err(e) = tx.try_send(positions) {
|
||||||
debug!("Failed to send cursor position to channel: {:?}", e);
|
debug!("Failed to send cursor position to channel: {:?}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use tauri::Manager;
|
|||||||
use tauri_plugin_positioner::WindowExt;
|
use tauri_plugin_positioner::WindowExt;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
pub static SCENE_WINDOW_LABEL: &str = "scene";
|
pub static SCENE_WINDOW_LABEL: &str = "scene";
|
||||||
|
pub static SPLASH_WINDOW_LABEL: &str = "splash";
|
||||||
|
|
||||||
pub fn overlay_fullscreen(window: &tauri::Window) -> Result<(), tauri::Error> {
|
pub fn overlay_fullscreen(window: &tauri::Window) -> Result<(), tauri::Error> {
|
||||||
// Get the primary monitor
|
// Get the primary monitor
|
||||||
@@ -22,6 +23,65 @@ pub fn overlay_fullscreen(window: &tauri::Window) -> Result<(), tauri::Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open_splash_window() {
|
||||||
|
let app_handle = get_app_handle();
|
||||||
|
let existing_webview_window = app_handle.get_window(SPLASH_WINDOW_LABEL);
|
||||||
|
|
||||||
|
if let Some(window) = existing_webview_window {
|
||||||
|
window.show().unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Starting splash window creation...");
|
||||||
|
let webview_window = match tauri::WebviewWindowBuilder::new(
|
||||||
|
app_handle,
|
||||||
|
SPLASH_WINDOW_LABEL,
|
||||||
|
tauri::WebviewUrl::App("/splash".into()),
|
||||||
|
)
|
||||||
|
.title("Friendolls Splash")
|
||||||
|
.inner_size(600.0, 300.0)
|
||||||
|
.resizable(false)
|
||||||
|
.decorations(false)
|
||||||
|
.transparent(true)
|
||||||
|
.shadow(false)
|
||||||
|
.visible(false) // Show it after centering
|
||||||
|
.skip_taskbar(true)
|
||||||
|
.always_on_top(true)
|
||||||
|
.build()
|
||||||
|
{
|
||||||
|
Ok(window) => {
|
||||||
|
info!("Splash window builder succeeded");
|
||||||
|
window
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to build splash window: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = webview_window.move_window(tauri_plugin_positioner::Position::Center) {
|
||||||
|
error!("Failed to move splash window to center: {}", e);
|
||||||
|
// Continue anyway
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = webview_window.show() {
|
||||||
|
error!("Failed to show splash window: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Splash window initialized successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close_splash_window() {
|
||||||
|
let app_handle = get_app_handle();
|
||||||
|
if let Some(window) = app_handle.get_window(SPLASH_WINDOW_LABEL) {
|
||||||
|
if let Err(e) = window.close() {
|
||||||
|
error!("Failed to close splash window: {}", e);
|
||||||
|
} else {
|
||||||
|
info!("Splash window closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn open_scene_window() {
|
pub fn open_scene_window() {
|
||||||
let app_handle = get_app_handle();
|
let app_handle = get_app_handle();
|
||||||
let existing_webview_window = app_handle.get_window(SCENE_WINDOW_LABEL);
|
let existing_webview_window = app_handle.get_window(SCENE_WINDOW_LABEL);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use std::{
|
|||||||
env,
|
env,
|
||||||
sync::{Arc, LazyLock, RwLock},
|
sync::{Arc, LazyLock, RwLock},
|
||||||
};
|
};
|
||||||
use tauri::{async_runtime, Emitter};
|
use tauri::Emitter;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
@@ -34,6 +34,7 @@ pub struct AppState {
|
|||||||
pub clients: Option<Clients>,
|
pub clients: Option<Clients>,
|
||||||
pub auth_pass: Option<AuthPass>,
|
pub auth_pass: Option<AuthPass>,
|
||||||
pub oauth_flow: OAuthFlowTracker,
|
pub oauth_flow: OAuthFlowTracker,
|
||||||
|
pub tracing_guard: Option<tracing_appender::non_blocking::WorkerGuard>,
|
||||||
|
|
||||||
// exposed to the frontend
|
// exposed to the frontend
|
||||||
pub app_data: AppData,
|
pub app_data: AppData,
|
||||||
@@ -44,10 +45,11 @@ pub struct AppState {
|
|||||||
pub static FDOLL: LazyLock<Arc<RwLock<AppState>>> =
|
pub static FDOLL: LazyLock<Arc<RwLock<AppState>>> =
|
||||||
LazyLock::new(|| Arc::new(RwLock::new(AppState::default())));
|
LazyLock::new(|| Arc::new(RwLock::new(AppState::default())));
|
||||||
|
|
||||||
pub fn init_fdoll_state() {
|
pub fn init_fdoll_state(tracing_guard: Option<tracing_appender::non_blocking::WorkerGuard>) {
|
||||||
{
|
{
|
||||||
let mut guard = lock_w!(FDOLL);
|
let mut guard = lock_w!(FDOLL);
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
|
guard.tracing_guard = tracing_guard;
|
||||||
guard.app_config = AppConfig {
|
guard.app_config = AppConfig {
|
||||||
api_base_url: Some(env::var("API_BASE_URL").expect("API_BASE_URL must be set")),
|
api_base_url: Some(env::var("API_BASE_URL").expect("API_BASE_URL must be set")),
|
||||||
auth: AuthConfig {
|
auth: AuthConfig {
|
||||||
|
|||||||
BIN
src/assets/media/splash-dev.jpeg
Normal file
BIN
src/assets/media/splash-dev.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
9
src/routes/splash/+page.svelte
Normal file
9
src/routes/splash/+page.svelte
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<div id="splash" class="w-screen h-screen object-contain bg-base-100"></div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#splash {
|
||||||
|
background-image: url("../../assets/media/splash-dev.jpeg");
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user