Mountain/Environment/WebviewProvider/
lifecycle.rs

1//! # WebviewProvider - Lifecycle Operations
2//!
3//! Implementation of webview panel lifecycle methods for
4//! [`MountainEnvironment`]
5//!
6//! Handles creation, disposal, and visibility management of webview panels.
7
8use CommonLibrary::{
9	Error::CommonError::CommonError,
10	Webview::DTO::WebviewContentOptionsDTO::WebviewContentOptionsDTO,
11};
12use log::{error, info, warn};
13use serde_json::{Value, json};
14use tauri::{Emitter, Manager, WebviewWindow, WebviewWindowBuilder};
15use uuid::Uuid;
16
17use super::super::{MountainEnvironment::MountainEnvironment, Utility};
18use crate::ApplicationState::DTO::WebviewStateDTO::WebviewStateDTO;
19
20/// Lifecycle operations implementation for MountainEnvironment
21pub(super) async fn create_webview_panel_impl(
22	env:&MountainEnvironment,
23	extension_data_value:Value,
24	view_type:String,
25	title:String,
26	_show_options_value:Value,
27	panel_options_value:Value,
28	content_options_value:Value,
29) -> Result<String, CommonError> {
30	let handle = Uuid::new_v4().to_string();
31
32	info!(
33		"[WebviewProvider] Creating WebviewPanel with handle: {}, viewType: {}",
34		handle, view_type
35	);
36
37	// Parse content options to ensure security settings
38	let content_options:WebviewContentOptionsDTO =
39		serde_json::from_value(content_options_value.clone()).map_err(|error| {
40			CommonError::InvalidArgument { ArgumentName:"ContentOptions".into(), Reason:error.to_string() }
41		})?;
42
43	let state = WebviewStateDTO {
44		Handle:handle.clone(),
45		ViewType:view_type.clone(),
46		Title:title.clone(),
47		ContentOptions:content_options,
48		PanelOptions:panel_options_value.clone(),
49		SideCarIdentifier:"cocoon-main".to_string(),
50		ExtensionIdentifier:extension_data_value
51			.get("id")
52			.and_then(|v| v.as_str())
53			.unwrap_or_default()
54			.to_string(),
55		IsActive:true,
56		IsVisible:true,
57	};
58
59	// Store the initial state with lifecycle state
60	{
61		let mut webview_guard = env
62			.ApplicationState
63			.Feature
64			.Webviews
65			.ActiveWebviews
66			.lock()
67			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
68
69		webview_guard.insert(handle.clone(), state);
70	}
71
72	// Create a new Tauri window for this webview with security settings
73	let title_clone = title.clone();
74	let _webview_window = WebviewWindowBuilder::new(
75		&env.ApplicationHandle,
76		&handle,
77		tauri::WebviewUrl::App("WebviewHost.html".into()),
78	)
79	.title(title)
80	.initialization_script(&format!(
81		"window.__WEBVIEW_INITIAL_STATE__ = {};",
82		json!({
83			"Handle": handle,
84			"ViewType": view_type,
85			"Title": title_clone
86		})
87	))
88	.build()
89	.map_err(|error| {
90		error!("[WebviewProvider] Failed to create Webview window: {}", error);
91		CommonError::UserInterfaceInteraction { Reason:error.to_string() }
92	})?;
93
94	// Setup message listener for this Webview
95	crate::Environment::WebviewProvider::messaging::setup_webview_message_listener_impl(env, handle.clone()).await?;
96
97	// Notify frontend about Webview creation
98	env.ApplicationHandle
99		.emit::<Value>(
100			"sky://webview/created",
101			json!({ "Handle": handle.clone(), "ViewType": view_type.clone(), "Title": title_clone }),
102		)
103		.map_err(|error| {
104			CommonError::IPCError { Description:format!("Failed to emit Webview creation event: {}", error) }
105		})?;
106
107	Ok(handle)
108}
109
110/// Disposes a Webview panel and cleans up all associated resources.
111pub(super) async fn dispose_webview_panel_impl(env:&MountainEnvironment, handle:String) -> Result<(), CommonError> {
112	info!("[WebviewProvider] Disposing WebviewPanel: {}", handle);
113
114	// Remove message listener
115	crate::Environment::WebviewProvider::messaging::remove_webview_message_listener_impl(env, &handle);
116
117	// Close the window
118	if let Some(webview_window) = env.ApplicationHandle.get_webview_window(&handle) {
119		if let Err(error) = webview_window.close() {
120			warn!("[WebviewProvider] Failed to close Webview window: {}", error);
121		}
122	}
123
124	// Remove state
125	env.ApplicationState
126		.Feature
127		.Webviews
128		.ActiveWebviews
129		.lock()
130		.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
131		.remove(&handle);
132
133	// Notify frontend about Webview disposal
134	env.ApplicationHandle
135		.emit::<Value>("sky://webview/disposed", json!({ "Handle": handle }))
136		.map_err(|error| {
137			CommonError::IPCError { Description:format!("Failed to emit Webview disposal event: {}", error) }
138		})?;
139
140	Ok(())
141}
142
143/// Reveals (shows and focuses) a Webview panel.
144pub(super) async fn reveal_webview_panel_impl(
145	env:&MountainEnvironment,
146	handle:String,
147	_show_options_value:Value,
148) -> Result<(), CommonError> {
149	info!("[WebviewProvider] Revealing WebviewPanel: {}", handle);
150
151	if let Some(webview_window) = env.ApplicationHandle.get_webview_window(&handle) {
152		webview_window.show().map_err(|error| {
153			CommonError::UserInterfaceInteraction { Reason:format!("Failed to show Webview window: {}", error) }
154		})?;
155
156		webview_window.set_focus().map_err(|error| {
157			CommonError::UserInterfaceInteraction { Reason:format!("Failed to focus Webview window: {}", error) }
158		})?;
159
160		// Update visibility state
161		{
162			let mut webview_guard = env
163				.ApplicationState
164				.Feature
165				.Webviews
166				.ActiveWebviews
167				.lock()
168				.map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
169
170			if let Some(state) = webview_guard.get_mut(&handle) {
171				state.IsVisible = true;
172			}
173		}
174
175		// Emit visibility event
176		env.ApplicationHandle
177			.emit::<Value>("sky://webview/revealed", json!({ "Handle": handle }))
178			.map_err(|error| {
179				CommonError::IPCError { Description:format!("Failed to emit Webview revealed event: {}", error) }
180			})?;
181	}
182
183	Ok(())
184}