From 68c42b34a1ccfd6cd2d5eac44aa83c7a95a1f9c5 Mon Sep 17 00:00:00 2001 From: Wind-Explorer Date: Tue, 17 Feb 2026 18:19:12 +0800 Subject: [PATCH] UI to show modules --- src-tauri/src/commands/app_data.rs | 18 ------ src-tauri/src/commands/app_state.rs | 25 ++++++++ src-tauri/src/commands/mod.rs | 2 +- src-tauri/src/lib.rs | 12 ++-- src-tauri/src/models/app_data.rs | 2 +- .../src/services/presence_modules/mod.rs | 12 +--- .../src/services/presence_modules/models.rs | 4 +- src-tauri/src/state/mod.rs | 18 ++++-- src/events/app-data.ts | 6 +- src/routes/app-menu/+page.svelte | 11 ++++ src/routes/app-menu/tabs/modules.svelte | 62 +++++++++++++++++++ src/types/bindings/ModuleMetadata.ts | 3 + .../bindings/{AppData.ts => UserData.ts} | 2 +- 13 files changed, 134 insertions(+), 43 deletions(-) delete mode 100644 src-tauri/src/commands/app_data.rs create mode 100644 src-tauri/src/commands/app_state.rs create mode 100644 src/routes/app-menu/tabs/modules.svelte create mode 100644 src/types/bindings/ModuleMetadata.ts rename src/types/bindings/{AppData.ts => UserData.ts} (68%) diff --git a/src-tauri/src/commands/app_data.rs b/src-tauri/src/commands/app_data.rs deleted file mode 100644 index 1d29adc..0000000 --- a/src-tauri/src/commands/app_data.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::{ - lock_r, - models::app_data::AppData, - state::{init_app_data_scoped, AppDataRefreshScope, FDOLL}, -}; - -#[tauri::command] -pub fn get_app_data() -> Result { - let guard = lock_r!(FDOLL); - Ok(guard.user_data.clone()) -} - -#[tauri::command] -pub async fn refresh_app_data() -> Result { - init_app_data_scoped(AppDataRefreshScope::All).await; - let guard = lock_r!(FDOLL); - Ok(guard.user_data.clone()) -} diff --git a/src-tauri/src/commands/app_state.rs b/src-tauri/src/commands/app_state.rs new file mode 100644 index 0000000..20dbe9e --- /dev/null +++ b/src-tauri/src/commands/app_state.rs @@ -0,0 +1,25 @@ +use crate::{ + lock_r, + models::app_data::UserData, + services::presence_modules::models::ModuleMetadata, + state::{init_app_data_scoped, AppDataRefreshScope, FDOLL}, +}; + +#[tauri::command] +pub fn get_app_data() -> Result { + let guard = lock_r!(FDOLL); + Ok(guard.user_data.clone()) +} + +#[tauri::command] +pub async fn refresh_app_data() -> Result { + init_app_data_scoped(AppDataRefreshScope::All).await; + let guard = lock_r!(FDOLL); + Ok(guard.user_data.clone()) +} + +#[tauri::command] +pub fn get_modules() -> Result, String> { + let guard = lock_r!(FDOLL); + Ok(guard.modules.metadatas.clone()) +} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index e041147..eb86c5f 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -1,5 +1,5 @@ pub mod app; -pub mod app_data; +pub mod app_state; pub mod auth; pub mod config; pub mod dolls; diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 2554605..c58ac19 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,9 +1,12 @@ -use crate::services::{ - doll_editor::open_doll_editor_window, - scene::{set_pet_menu_state, set_scene_interactive}, +use crate::{ + commands::app_state::get_modules, + services::{ + doll_editor::open_doll_editor_window, + scene::{set_pet_menu_state, set_scene_interactive}, + }, }; use commands::app::{quit_app, restart_app, retry_connection}; -use commands::app_data::{get_app_data, refresh_app_data}; +use commands::app_state::{get_app_data, refresh_app_data}; use commands::auth::{change_password, login, logout_and_restart, register, reset_password}; use commands::config::{get_client_config, open_client_config_manager, save_client_config}; use commands::dolls::{ @@ -86,6 +89,7 @@ pub fn run() { reset_password, logout_and_restart, send_interaction_cmd, + get_modules ]) .setup(|app| { APP_HANDLE diff --git a/src-tauri/src/models/app_data.rs b/src-tauri/src/models/app_data.rs index 14192d7..4e0488e 100644 --- a/src-tauri/src/models/app_data.rs +++ b/src-tauri/src/models/app_data.rs @@ -39,7 +39,7 @@ impl Default for SceneData { #[derive(Default, Serialize, Deserialize, Clone, Debug, TS)] #[ts(export)] -pub struct AppData { +pub struct UserData { pub user: Option, pub friends: Option>, pub dolls: Option>, diff --git a/src-tauri/src/services/presence_modules/mod.rs b/src-tauri/src/services/presence_modules/mod.rs index 5d65c3c..4350e28 100644 --- a/src-tauri/src/services/presence_modules/mod.rs +++ b/src-tauri/src/services/presence_modules/mod.rs @@ -60,14 +60,7 @@ pub fn init_modules() { } }; - let state = lock_w!(crate::state::FDOLL); - let mut state_guard = match state.module_handles.lock() { - Ok(guard) => guard, - Err(e) => { - error!("Failed to lock module handles: {}", e); - return; - } - }; + let mut state = lock_w!(crate::state::FDOLL); for entry in entries { let entry = match entry { @@ -88,7 +81,8 @@ pub fn init_modules() { if script_path.exists() { match runtime::spawn_lua_runtime_from_path(&script_path) { Ok(handle) => { - state_guard.push(handle); + state.modules.metadatas.push(module_metadata.clone()); + state.modules.handles.lock().unwrap().push(handle); } Err(e) => { error!( diff --git a/src-tauri/src/services/presence_modules/models.rs b/src-tauri/src/services/presence_modules/models.rs index 453882c..c599299 100644 --- a/src-tauri/src/services/presence_modules/models.rs +++ b/src-tauri/src/services/presence_modules/models.rs @@ -10,7 +10,9 @@ pub struct PresenceStatus { pub graphics_b64: Option, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export)] pub struct ModuleMetadata { pub name: String, pub version: String, diff --git a/src-tauri/src/state/mod.rs b/src-tauri/src/state/mod.rs index 6a0ffa8..142f831 100644 --- a/src-tauri/src/state/mod.rs +++ b/src-tauri/src/state/mod.rs @@ -1,5 +1,7 @@ // in app-core/src/state.rs -use crate::{lock_w, models::app_data::AppData}; +use crate::{ + lock_w, models::app_data::UserData, services::presence_modules::models::ModuleMetadata, +}; use std::sync::{Arc, LazyLock, RwLock}; use tauri::tray::TrayIcon; use tracing::info; @@ -12,14 +14,20 @@ pub use auth::*; pub use network::*; pub use ui::*; +#[derive(Default)] +pub struct Modules { + pub handles: std::sync::Mutex>>, + pub metadatas: Vec, +} + #[derive(Default)] pub struct AppState { pub app_config: crate::services::client_config_manager::AppConfig, pub network: NetworkState, pub auth: AuthState, - pub user_data: AppData, + pub user_data: UserData, pub tray: Option, - pub module_handles: std::sync::Mutex>>, + pub modules: Modules, } // Global application state @@ -36,8 +44,8 @@ pub fn init_app_state() { guard.app_config = crate::services::client_config_manager::load_app_config(); guard.network = init_network_state(); guard.auth = init_auth_state(); - guard.user_data = AppData::default(); - guard.module_handles = std::sync::Mutex::new(Vec::new()); + guard.user_data = UserData::default(); + guard.modules = Modules::default(); } update_display_dimensions_for_scene_state(); info!("Initialized FDOLL state (WebSocket client & user data initializing asynchronously)"); diff --git a/src/events/app-data.ts b/src/events/app-data.ts index c0aa7f8..fef0875 100644 --- a/src/events/app-data.ts +++ b/src/events/app-data.ts @@ -1,9 +1,9 @@ import { writable } from "svelte/store"; -import { type AppData } from "../types/bindings/AppData"; +import { type UserData } from "../types/bindings/UserData"; import { listen, type UnlistenFn } from "@tauri-apps/api/event"; import { invoke } from "@tauri-apps/api/core"; -export let appData = writable(null); +export let appData = writable(null); let unlisten: UnlistenFn | null = null; let isListening = false; @@ -12,7 +12,7 @@ export async function initAppDataListener() { try { if (isListening) return; appData.set(await invoke("get_app_data")); - unlisten = await listen("app-data-refreshed", (event) => { + unlisten = await listen("app-data-refreshed", (event) => { console.log("app-data-refreshed", event.payload); appData.set(event.payload); }); diff --git a/src/routes/app-menu/+page.svelte b/src/routes/app-menu/+page.svelte index da5b49f..fe0233f 100644 --- a/src/routes/app-menu/+page.svelte +++ b/src/routes/app-menu/+page.svelte @@ -1,6 +1,7 @@ + +
+ {#if error} +
{error}
+ {/if} + +
+
+ +
+ Loaded Presence Modules +
+
+
+ {#if loading} +

Loading modules...

+ {:else if modules.length === 0} +

No modules loaded.

+ {:else} +
+ {#each modules as module (module.name)} +
+
+
{module.name}
+
+ Version: {module.version} +
+ {#if module.description} +
+ {module.description} +
+ {/if} +
+
+ {/each} +
+ {/if} +
+
+
+
+
diff --git a/src/types/bindings/ModuleMetadata.ts b/src/types/bindings/ModuleMetadata.ts new file mode 100644 index 0000000..16e905b --- /dev/null +++ b/src/types/bindings/ModuleMetadata.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ModuleMetadata = { name: string, version: string, description: string | null, }; diff --git a/src/types/bindings/AppData.ts b/src/types/bindings/UserData.ts similarity index 68% rename from src/types/bindings/AppData.ts rename to src/types/bindings/UserData.ts index b45136f..d2786e3 100644 --- a/src/types/bindings/AppData.ts +++ b/src/types/bindings/UserData.ts @@ -4,4 +4,4 @@ import type { FriendshipResponseDto } from "./FriendshipResponseDto"; import type { SceneData } from "./SceneData"; import type { UserProfile } from "./UserProfile"; -export type AppData = { user: UserProfile | null, friends: Array | null, dolls: Array | null, scene: SceneData, }; +export type UserData = { user: UserProfile | null, friends: Array | null, dolls: Array | null, scene: SceneData, };