a471e69455
桌面壳生命周期按可见性、最小化和焦点统一归一 托盘隐藏前注入 background 并在恢复窗口时回放当前状态 H5 lifecycle 测试覆盖 background 暂停语义 宿主壳文档和原生壳门禁同步桌面 background 约定
160 lines
4.5 KiB
Rust
160 lines
4.5 KiB
Rust
use crate::shell::events::host_bridge_event_script;
|
|
use crate::shell::navigation::register_desktop_navigation_events;
|
|
use crate::shell::network::register_desktop_network_events;
|
|
use serde_json::json;
|
|
use tauri::webview::PageLoadEvent;
|
|
use tauri::{WebviewWindow, WindowEvent};
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) struct DesktopLifecyclePayload {
|
|
state: &'static str,
|
|
focused: bool,
|
|
native_state: &'static str,
|
|
}
|
|
|
|
pub(crate) fn resolve_desktop_lifecycle_payload(
|
|
focused: bool,
|
|
visible: bool,
|
|
minimized: bool,
|
|
) -> DesktopLifecyclePayload {
|
|
if !visible {
|
|
return DesktopLifecyclePayload {
|
|
state: "background",
|
|
focused: false,
|
|
native_state: "hidden",
|
|
};
|
|
}
|
|
|
|
if minimized {
|
|
return DesktopLifecyclePayload {
|
|
state: "background",
|
|
focused: false,
|
|
native_state: "minimized",
|
|
};
|
|
}
|
|
|
|
if focused {
|
|
DesktopLifecyclePayload {
|
|
state: "active",
|
|
focused: true,
|
|
native_state: "focused",
|
|
}
|
|
} else {
|
|
DesktopLifecyclePayload {
|
|
state: "inactive",
|
|
focused: false,
|
|
native_state: "blurred",
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn emit_desktop_lifecycle_event(
|
|
window: &WebviewWindow,
|
|
state: &'static str,
|
|
focused: bool,
|
|
native_state: &'static str,
|
|
) -> tauri::Result<()> {
|
|
let script = host_bridge_event_script(
|
|
"app.lifecycle",
|
|
json!({
|
|
"state": state,
|
|
"focused": focused,
|
|
"nativeState": native_state,
|
|
}),
|
|
)
|
|
.map_err(tauri::Error::Json)?;
|
|
|
|
window.eval(script)
|
|
}
|
|
|
|
pub(crate) fn emit_desktop_lifecycle_payload(
|
|
window: &WebviewWindow,
|
|
payload: DesktopLifecyclePayload,
|
|
) -> tauri::Result<()> {
|
|
emit_desktop_lifecycle_event(window, payload.state, payload.focused, payload.native_state)
|
|
}
|
|
|
|
pub(crate) fn emit_current_desktop_lifecycle_event(window: &WebviewWindow) -> tauri::Result<()> {
|
|
let visible = window.is_visible().unwrap_or(true);
|
|
let minimized = window.is_minimized().unwrap_or(false);
|
|
let focused = window.is_focused().unwrap_or(visible && !minimized);
|
|
emit_desktop_lifecycle_payload(
|
|
window,
|
|
resolve_desktop_lifecycle_payload(focused, visible, minimized),
|
|
)
|
|
}
|
|
|
|
pub(crate) fn register_desktop_lifecycle_events(window: &WebviewWindow) {
|
|
let lifecycle_window = window.clone();
|
|
window.on_window_event(move |event| {
|
|
if matches!(event, WindowEvent::Focused(_) | WindowEvent::Resized(_)) {
|
|
let _ = emit_current_desktop_lifecycle_event(&lifecycle_window);
|
|
}
|
|
});
|
|
}
|
|
|
|
pub(crate) fn should_replay_desktop_webview_state_on_page_load(event: PageLoadEvent) -> bool {
|
|
event == PageLoadEvent::Finished
|
|
}
|
|
|
|
pub(crate) fn replay_desktop_webview_state(window: &WebviewWindow) {
|
|
let _ = emit_current_desktop_lifecycle_event(window);
|
|
let _ = register_desktop_network_events(window);
|
|
let _ = register_desktop_navigation_events(window);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn desktop_page_load_replays_state_only_after_finished_load() {
|
|
assert!(should_replay_desktop_webview_state_on_page_load(
|
|
PageLoadEvent::Finished
|
|
));
|
|
assert!(!should_replay_desktop_webview_state_on_page_load(
|
|
PageLoadEvent::Started
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn desktop_lifecycle_payload_maps_hidden_and_minimized_to_background() {
|
|
assert_eq!(
|
|
resolve_desktop_lifecycle_payload(true, false, false),
|
|
DesktopLifecyclePayload {
|
|
state: "background",
|
|
focused: false,
|
|
native_state: "hidden",
|
|
}
|
|
);
|
|
assert_eq!(
|
|
resolve_desktop_lifecycle_payload(true, true, true),
|
|
DesktopLifecyclePayload {
|
|
state: "background",
|
|
focused: false,
|
|
native_state: "minimized",
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn desktop_lifecycle_payload_maps_visible_focus_state() {
|
|
assert_eq!(
|
|
resolve_desktop_lifecycle_payload(true, true, false),
|
|
DesktopLifecyclePayload {
|
|
state: "active",
|
|
focused: true,
|
|
native_state: "focused",
|
|
}
|
|
);
|
|
assert_eq!(
|
|
resolve_desktop_lifecycle_payload(false, true, false),
|
|
DesktopLifecyclePayload {
|
|
state: "inactive",
|
|
focused: false,
|
|
native_state: "blurred",
|
|
}
|
|
);
|
|
}
|
|
}
|