Skip to main content

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