瀏覽代碼

feat(core): MenuHandle `show`, `hide`, `is_visible` and `toggle` APIs (#1958)

Lucas Fernandes Nogueira 4 年之前
父節點
當前提交
954460c520

+ 5 - 0
.changes/core-show-hide-menu.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch
+---
+
+Adds `show`, `hide`, `is_visible` and `toggle` APIs to the `MenuHandle`.

+ 6 - 0
.changes/runtime-show-hide-menu.md

@@ -0,0 +1,6 @@
+---
+"tauri-runtime": patch
+"tauri-runtime-wry": patch
+---
+
+Adds `show_menu`, `hide_menu` and `is_menu_visible` APIs to the `Dispatcher` trait.

+ 1 - 1
Cargo.toml

@@ -23,7 +23,7 @@ members = [
 ]
 
 [patch.crates-io]
-tao = { git = "https://github.com/tauri-apps/tao", rev = "5be88eb9488e3ad27194b5eff2ea31a473128f9c" }
+tao = { git = "https://github.com/tauri-apps/tao", rev = "66360eea4ec6af8a52afcebb7700f486a0092168" }
 
 # default to small, optimized workspace release binaries
 [profile.release]

+ 50 - 0
core/tauri-runtime-wry/src/lib.rs

@@ -57,6 +57,9 @@ use std::{
   },
 };
 
+#[cfg(feature = "menu")]
+use std::sync::atomic::{AtomicBool, Ordering};
+
 #[cfg(any(feature = "menu", feature = "system-tray"))]
 mod menu;
 #[cfg(any(feature = "menu", feature = "system-tray"))]
@@ -456,6 +459,8 @@ enum WindowMessage {
   IsDecorated(Sender<bool>),
   IsResizable(Sender<bool>),
   IsVisible(Sender<bool>),
+  #[cfg(feature = "menu")]
+  IsMenuVisible(Sender<bool>),
   CurrentMonitor(Sender<Option<MonitorHandle>>),
   PrimaryMonitor(Sender<Option<MonitorHandle>>),
   AvailableMonitors(Sender<Vec<MonitorHandle>>),
@@ -469,6 +474,10 @@ enum WindowMessage {
   Unmaximize,
   Minimize,
   Unminimize,
+  #[cfg(feature = "menu")]
+  ShowMenu,
+  #[cfg(feature = "menu")]
+  HideMenu,
   Show,
   Hide,
   Close,
@@ -618,6 +627,11 @@ impl Dispatch for WryDispatcher {
     Ok(dispatcher_getter!(self, WindowMessage::IsVisible))
   }
 
+  #[cfg(feature = "menu")]
+  fn is_menu_visible(&self) -> Result<bool> {
+    Ok(dispatcher_getter!(self, WindowMessage::IsMenuVisible))
+  }
+
   fn current_monitor(&self) -> Result<Option<Monitor>> {
     Ok(
       dispatcher_getter!(self, WindowMessage::CurrentMonitor)
@@ -741,6 +755,24 @@ impl Dispatch for WryDispatcher {
       .map_err(|_| Error::FailedToSendMessage)
   }
 
+  #[cfg(feature = "menu")]
+  fn show_menu(&self) -> Result<()> {
+    self
+      .context
+      .proxy
+      .send_event(Message::Window(self.window_id, WindowMessage::ShowMenu))
+      .map_err(|_| Error::FailedToSendMessage)
+  }
+
+  #[cfg(feature = "menu")]
+  fn hide_menu(&self) -> Result<()> {
+    self
+      .context
+      .proxy
+      .send_event(Message::Window(self.window_id, WindowMessage::HideMenu))
+      .map_err(|_| Error::FailedToSendMessage)
+  }
+
   fn show(&self) -> Result<()> {
     self
       .context
@@ -916,6 +948,8 @@ struct WebviewWrapper {
   inner: WebView,
   #[cfg(feature = "menu")]
   menu_items: HashMap<u32, WryCustomMenuItem>,
+  #[cfg(feature = "menu")]
+  is_menu_visible: AtomicBool,
 }
 
 /// A Tauri [`Runtime`] wrapper around wry.
@@ -1275,6 +1309,10 @@ fn handle_event_loop(
             WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(),
             WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(),
             WindowMessage::IsVisible(tx) => tx.send(window.is_visible()).unwrap(),
+            #[cfg(feature = "menu")]
+            WindowMessage::IsMenuVisible(tx) => tx
+              .send(webview.is_menu_visible.load(Ordering::Relaxed))
+              .unwrap(),
             WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(),
             WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(),
             WindowMessage::AvailableMonitors(tx) => {
@@ -1295,6 +1333,16 @@ fn handle_event_loop(
             WindowMessage::Unmaximize => window.set_maximized(false),
             WindowMessage::Minimize => window.set_minimized(true),
             WindowMessage::Unminimize => window.set_minimized(false),
+            #[cfg(feature = "menu")]
+            WindowMessage::ShowMenu => {
+              window.show_menu();
+              webview.is_menu_visible.store(true, Ordering::Relaxed);
+            }
+            #[cfg(feature = "menu")]
+            WindowMessage::HideMenu => {
+              window.hide_menu();
+              webview.is_menu_visible.store(false, Ordering::Relaxed);
+            }
             WindowMessage::Show => window.set_visible(true),
             WindowMessage::Hide => window.set_visible(false),
             WindowMessage::Close => {
@@ -1494,6 +1542,8 @@ fn create_webview<P: Params<Runtime = Wry>>(
     inner: webview,
     #[cfg(feature = "menu")]
     menu_items,
+    #[cfg(feature = "menu")]
+    is_menu_visible: AtomicBool::new(true),
   })
 }
 

+ 12 - 0
core/tauri-runtime/src/lib.rs

@@ -301,6 +301,10 @@ pub trait Dispatch: Clone + Send + Sized + 'static {
   /// Gets the window's current vibility state.
   fn is_visible(&self) -> crate::Result<bool>;
 
+  /// Gets the window menu current visibility state.
+  #[cfg(feature = "menu")]
+  fn is_menu_visible(&self) -> crate::Result<bool>;
+
   /// Returns the monitor on which the window currently resides.
   ///
   /// Returns None if current monitor can't be detected.
@@ -350,6 +354,14 @@ pub trait Dispatch: Clone + Send + Sized + 'static {
   /// Unminimizes the window.
   fn unminimize(&self) -> crate::Result<()>;
 
+  /// Shows the window menu.
+  #[cfg(feature = "menu")]
+  fn show_menu(&self) -> crate::Result<()>;
+
+  /// Hides the window menu.
+  #[cfg(feature = "menu")]
+  fn hide_menu(&self) -> crate::Result<()>;
+
   /// Shows the window.
   fn show(&self) -> crate::Result<()>;
 

+ 24 - 0
core/tauri/src/window/menu.rs

@@ -70,6 +70,30 @@ impl<P: Params> MenuHandle<P> {
     }
     panic!("item id not found")
   }
+
+  /// Shows the menu.
+  pub fn show(&self) -> crate::Result<()> {
+    self.dispatcher.show_menu().map_err(Into::into)
+  }
+
+  /// Hides the menu.
+  pub fn hide(&self) -> crate::Result<()> {
+    self.dispatcher.hide_menu().map_err(Into::into)
+  }
+
+  /// Whether the menu is visible or not.
+  pub fn is_visible(&self) -> crate::Result<bool> {
+    self.dispatcher.is_menu_visible().map_err(Into::into)
+  }
+
+  /// Toggles the menu visibility.
+  pub fn toggle(&self) -> crate::Result<()> {
+    if self.is_visible()? {
+      self.hide()
+    } else {
+      self.show()
+    }
+  }
 }
 
 impl<P: Params> MenuItemHandle<P> {

+ 1 - 0
examples/api/package.json

@@ -18,6 +18,7 @@
   },
   "dependencies": {
     "@tauri-apps/api": "link:../../tooling/api/dist",
+    "hotkeys-js": "^3.8.5",
     "sirv-cli": "1.0.11"
   }
 }

File diff suppressed because it is too large
+ 0 - 0
examples/api/public/build/bundle.js


File diff suppressed because it is too large
+ 0 - 0
examples/api/public/build/bundle.js.map


+ 7 - 1
examples/api/src-tauri/src/main.rs

@@ -20,6 +20,11 @@ struct Reply {
   data: String,
 }
 
+#[tauri::command]
+async fn menu_toggle(window: tauri::Window) {
+  window.menu_handle().toggle().unwrap();
+}
+
 fn main() {
   tauri::Builder::default()
     .on_page_load(|window, _| {
@@ -86,7 +91,8 @@ fn main() {
     })
     .invoke_handler(tauri::generate_handler![
       cmd::log_operation,
-      cmd::perform_request
+      cmd::perform_request,
+      menu_toggle,
     ])
     .run(tauri::generate_context!())
     .expect("error while running tauri application");

+ 10 - 0
examples/api/src/App.svelte

@@ -1,6 +1,8 @@
 <script>
   import { onMount } from "svelte";
+  import hotkeys from "hotkeys-js";
   import { open } from "@tauri-apps/api/shell";
+  import { invoke } from "@tauri-apps/api/tauri";
 
   import Welcome from "./components/Welcome.svelte";
   import Cli from "./components/Cli.svelte";
@@ -14,6 +16,14 @@
   import Shell from "./components/Shell.svelte";
   import Updater from "./components/Updater.svelte";
 
+  const MENU_TOGGLE_HOTKEY = 'ctrl+b';
+
+  onMount(() => {
+    hotkeys(MENU_TOGGLE_HOTKEY, () => {
+      invoke('menu_toggle');
+    });
+  });
+
   const views = [
     {
       label: "Welcome",

+ 4 - 3
examples/api/src/components/Welcome.svelte

@@ -1,13 +1,14 @@
 <script>
   import { getName, getVersion, getTauriVersion } from "@tauri-apps/api/app";
   import { relaunch, exit } from "@tauri-apps/api/process";
+
   let version = 0.0;
   let tauriVersion = 0.0;
   let appName = 'Unknown';
 
-  getName().then(n => {appName = n});
-  getVersion().then(v => {version = v});
-  getTauriVersion().then(v => {tauriVersion = v});
+  getName().then(n => { appName = n });
+  getVersion().then(v => { version = v });
+  getTauriVersion().then(v => { tauriVersion = v });
 
   async function closeApp() {
     await exit();

+ 5 - 0
examples/api/yarn.lock

@@ -287,6 +287,11 @@ has@^1.0.3:
   dependencies:
     function-bind "^1.1.1"
 
+hotkeys-js@^3.8.5:
+  version "3.8.5"
+  resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.8.5.tgz#a66030c48b75ceb2f3fc48fd39e7a0b3473a4b19"
+  integrity sha512-beJJ2Y4J6XkSlXlLPOG29BRKxZx3bV0gVi3eUpYdjrecN1i25iqndM/+X1eIDPSeG0XdqSv7Ksek43j5tQrmPQ==
+
 inflight@^1.0.4:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"

+ 1 - 1
tooling/cli.js/test/jest/__tests__/template.spec.js

@@ -27,7 +27,7 @@ describe('[CLI] cli.js template', () => {
     const manifestFile = readFileSync(manifestPath).toString()
     writeFileSync(
       manifestPath,
-      `workspace = { }\n[patch.crates-io]\ntao = { git = "https://github.com/tauri-apps/tao", rev = "5be88eb9488e3ad27194b5eff2ea31a473128f9c" }\n\n${manifestFile}`
+      `workspace = { }\n[patch.crates-io]\ntao = { git = "https://github.com/tauri-apps/tao", rev = "66360eea4ec6af8a52afcebb7700f486a0092168" }\n\n${manifestFile}`
     )
 
     const { promise: buildPromise } = await build()

Some files were not shown because too many files changed in this diff