diff --git a/.changes/remove-tray-icon-mobile.md b/.changes/remove-tray-icon-mobile.md new file mode 100644 index 00000000000..f18cd377969 --- /dev/null +++ b/.changes/remove-tray-icon-mobile.md @@ -0,0 +1,6 @@ +--- +"tauri-codegen": patch +"tauri": patch +--- + +Refactor the `Context` conditional fields and only parse the tray icon on desktop. diff --git a/core/tauri-codegen/src/context.rs b/core/tauri-codegen/src/context.rs index 619be21b8aa..643ada6a8fe 100644 --- a/core/tauri-codegen/src/context.rs +++ b/core/tauri-codegen/src/context.rs @@ -125,6 +125,16 @@ enum Target { Ios, } +impl Target { + fn is_mobile(&self) -> bool { + matches!(self, Target::Android | Target::Ios) + } + + fn is_desktop(&self) -> bool { + !self.is_mobile() + } +} + /// Build a `tauri::Context` for including in application code. pub fn context_codegen(data: ContextData) -> Result { let ContextData { @@ -247,7 +257,7 @@ pub fn context_codegen(data: ContextData) -> Result Result Result Result Result Result quote!(::std::option::Option::None), - ShellAllowlistOpen::Flag(true) => { - quote!(::std::option::Option::Some(#root::regex::Regex::new(r#"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+"#).unwrap())) - } + let shell_scope_constructor = match &config.tauri.allowlist.shell.open { + ShellAllowlistOpen::Flag(false) => quote!(#root::ShellScopeConfig::new().skip_validation()), + ShellAllowlistOpen::Flag(true) => quote!(#root::ShellScopeConfig::new()), ShellAllowlistOpen::Validate(regex) => match Regex::new(regex) { - Ok(_) => quote!(::std::option::Option::Some(#root::regex::Regex::new(#regex).unwrap())), + Ok(_) => { + quote!(#root::ShellScopeConfig::with_validator(#root::regex::Regex::new(#regex).unwrap())) + } Err(error) => { let error = error.to_string(); quote!({ compile_error!(#error); - ::std::option::Option::Some(#root::regex::Regex::new(#regex).unwrap()) + #root::ShellScopeConfig::with_validator(#root::regex::Regex::new(#regex).unwrap()) }) } }, _ => panic!("unknown shell open format, unable to prepare"), }; + let shell_scope = quote!(#shell_scope_constructor.set_allowed_commands(#shell_scopes)); - quote!(#root::ShellScopeConfig { - open: #shell_scope_open, - scopes: #shell_scopes - }) + quote!(context.set_shell_scope(#shell_scope);) }; #[cfg(not(feature = "shell-scope"))] - let shell_scope_config = quote!(); - - Ok(quote!(#root::Context::new( - #config, - ::std::sync::Arc::new(#assets), - #default_window_icon, - #app_icon, - #system_tray_icon, - #package_info, - #info_plist, - #pattern, - #shell_scope_config - ))) + let with_shell_scope_code = quote!(); + + Ok(quote!({ + #[allow(unused_mut, clippy::let_and_return)] + let mut context = #root::Context::new( + #config, + ::std::sync::Arc::new(#assets), + #default_window_icon, + #app_icon, + #package_info, + #info_plist, + #pattern, + ); + #with_system_tray_icon_code + #with_shell_scope_code + context + })) } fn ico_icon>( @@ -483,7 +501,7 @@ fn ico_icon>( let out_path = out_path.display().to_string(); - let icon = quote!(Some(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height })); + let icon = quote!(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height }); Ok(icon) } @@ -501,7 +519,9 @@ fn raw_icon>(out_dir: &Path, path: P) -> Result>( let out_path = out_path.display().to_string(); - let icon = quote!(Some(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height })); + let icon = quote!(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height }); Ok(icon) } diff --git a/core/tauri/src/lib.rs b/core/tauri/src/lib.rs index ed7af0926a0..e7a1dda10ba 100644 --- a/core/tauri/src/lib.rs +++ b/core/tauri/src/lib.rs @@ -539,6 +539,7 @@ pub struct Context { pub(crate) assets: Arc, pub(crate) default_window_icon: Option, pub(crate) app_icon: Option>, + #[cfg(desktop)] pub(crate) system_tray_icon: Option, pub(crate) package_info: PackageInfo, pub(crate) _info_plist: (), @@ -553,9 +554,12 @@ impl fmt::Debug for Context { d.field("config", &self.config) .field("default_window_icon", &self.default_window_icon) .field("app_icon", &self.app_icon) - .field("system_tray_icon", &self.system_tray_icon) .field("package_info", &self.package_info) .field("pattern", &self.pattern); + + #[cfg(desktop)] + d.field("system_tray_icon", &self.system_tray_icon); + #[cfg(shell_scope)] d.field("shell_scope", &self.shell_scope); d.finish() @@ -600,12 +604,14 @@ impl Context { } /// The icon to use on the system tray UI. + #[cfg(desktop)] #[inline(always)] pub fn system_tray_icon(&self) -> Option<&Icon> { self.system_tray_icon.as_ref() } /// A mutable reference to the icon to use on the system tray UI. + #[cfg(desktop)] #[inline(always)] pub fn system_tray_icon_mut(&mut self) -> &mut Option { &mut self.system_tray_icon @@ -644,25 +650,38 @@ impl Context { assets: Arc, default_window_icon: Option, app_icon: Option>, - system_tray_icon: Option, package_info: PackageInfo, info_plist: (), pattern: Pattern, - #[cfg(shell_scope)] shell_scope: scope::ShellScopeConfig, ) -> Self { Self { config, assets, default_window_icon, app_icon, - system_tray_icon, + #[cfg(desktop)] + system_tray_icon: None, package_info, _info_plist: info_plist, pattern, #[cfg(shell_scope)] - shell_scope, + shell_scope: Default::default(), } } + + /// Sets the app tray icon. + #[cfg(desktop)] + #[inline(always)] + pub fn set_system_tray_icon(&mut self, icon: Icon) { + self.system_tray_icon.replace(icon); + } + + /// Sets the app shell scope. + #[cfg(shell_scope)] + #[inline(always)] + pub fn set_shell_scope(&mut self, scope: scope::ShellScopeConfig) { + self.shell_scope = scope; + } } // TODO: expand these docs diff --git a/core/tauri/src/manager.rs b/core/tauri/src/manager.rs index 37e08aaa95c..3a4c4bd9fb7 100644 --- a/core/tauri/src/manager.rs +++ b/core/tauri/src/manager.rs @@ -219,6 +219,7 @@ pub struct InnerWindowManager { assets: Arc, pub(crate) default_window_icon: Option, pub(crate) app_icon: Option>, + #[cfg(desktop)] pub(crate) tray_icon: Option, package_info: PackageInfo, @@ -240,17 +241,21 @@ pub struct InnerWindowManager { impl fmt::Debug for InnerWindowManager { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("InnerWindowManager") - .field("plugins", &self.plugins) + let mut d = f.debug_struct("InnerWindowManager"); + + d.field("plugins", &self.plugins) .field("state", &self.state) .field("config", &self.config) .field("default_window_icon", &self.default_window_icon) .field("app_icon", &self.app_icon) - .field("tray_icon", &self.tray_icon) .field("package_info", &self.package_info) .field("menu", &self.menu) - .field("pattern", &self.pattern) - .finish() + .field("pattern", &self.pattern); + + #[cfg(desktop)] + d.field("tray_icon", &self.tray_icon); + + d.finish() } } @@ -322,6 +327,7 @@ impl WindowManager { assets: context.assets, default_window_icon: context.default_window_icon, app_icon: context.app_icon, + #[cfg(desktop)] tray_icon: context.system_tray_icon, package_info: context.package_info, pattern: context.pattern, diff --git a/core/tauri/src/scope/shell.rs b/core/tauri/src/scope/shell.rs index a03644a090a..4d1aba537ba 100644 --- a/core/tauri/src/scope/shell.rs +++ b/core/tauri/src/scope/shell.rs @@ -12,6 +12,8 @@ use regex::Regex; use std::collections::HashMap; +const DEFAULT_OPEN_REGEX: &str = r#"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+"#; + /// Allowed representation of `Execute` command arguments. #[derive(Debug, Clone, serde::Deserialize)] #[serde(untagged, deny_unknown_fields)] @@ -67,6 +69,45 @@ pub struct ScopeConfig { pub scopes: HashMap, } +impl Default for ScopeConfig { + fn default() -> Self { + Self { + open: Some(Regex::new(DEFAULT_OPEN_REGEX).unwrap()), + scopes: Default::default(), + } + } +} + +impl ScopeConfig { + /// Creates a new scope configuration with the default validation regex ^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+. + pub fn new() -> Self { + Self::default() + } + + /// Creates a new scope configuration with the specified validation regex. + pub fn with_validator(regex: Regex) -> Self { + Self { + open: Some(regex), + scopes: Default::default(), + } + } + + /// Unsets the validator regex, allowing any path to be opened. + pub fn skip_validation(mut self) -> Self { + self.open = None; + self + } + + /// Sets the commands that are allowed to be executed. + pub fn set_allowed_commands>( + mut self, + scopes: I, + ) -> Self { + self.scopes = scopes.into_iter().collect(); + self + } +} + /// A configured scoped shell command. #[derive(Debug, Clone)] pub struct ScopeAllowedCommand { diff --git a/core/tauri/src/test/mod.rs b/core/tauri/src/test/mod.rs index f31789c49e3..22d4acf5b97 100644 --- a/core/tauri/src/test/mod.rs +++ b/core/tauri/src/test/mod.rs @@ -60,6 +60,7 @@ pub fn mock_context(assets: A) -> crate::Context { assets: Arc::new(assets), default_window_icon: None, app_icon: None, + #[cfg(desktop)] system_tray_icon: None, package_info: crate::PackageInfo { name: "test".into(),