feat(stage-tamagotchi): support to modify the window mode from tray

This commit is contained in:
Ayaka Neko
2025-08-21 01:25:36 +08:00
parent a988ba2512
commit d6380ece7b
5 changed files with 91 additions and 26 deletions
@@ -105,10 +105,27 @@ pub fn run() {
],
)?;
let window_mode_fade_on_hover = MenuItem::with_id(app, "window-mode.fade-on-hover", "Fade On Hover", true, None::<&str>)?;
let window_mode_move = MenuItem::with_id(app, "window-mode.move", "Move", true, None::<&str>)?;
let window_mode_resize = MenuItem::with_id(app, "window-mode.resize", "Resize", true, None::<&str>)?;
let window_mode_sub_menu = Submenu::with_id_and_items(
app,
"window-mode",
"Window Mode",
true,
&[
&window_mode_fade_on_hover,
&window_mode_move,
&window_mode_resize,
],
)?;
let menu = Menu::with_items(
app,
&[
&settings_item,
&window_mode_sub_menu,
&position_sub_menu,
&hide_item,
&show_item,
@@ -142,6 +159,24 @@ pub fn run() {
app::windows::settings::new_settings_window(app, None).unwrap();
}
"window-mode.fade-on-hover" => {
let window = app.get_webview_window("main");
if let Some(window) = window {
window.emit("tauri-main:main:window-mode:fade-on-hover", true).map_err(|_| ()).unwrap();
}
}
"window-mode.move" => {
let window = app.get_webview_window("main");
if let Some(window) = window {
window.emit("tauri-main:main:window-mode:move", true).map_err(|_| ()).unwrap();
}
}
"window-mode.resize" => {
let window = app.get_webview_window("main");
if let Some(window) = window {
window.emit("tauri-main:main:window-mode:resize", true).map_err(|_| ()).unwrap();
}
}
"center" => {
let _ = app.get_webview_window("main")
.ok_or(())
+2 -8
View File
@@ -3,7 +3,6 @@ import type { AiriTamagotchiEvents } from './composables/tauri'
import { useMcpStore, useOnboardingStore, useSettings } from '@proj-airi/stage-ui/stores'
import { Window } from '@tauri-apps/api/window'
import { useEventListener } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { computed, onMounted, watch } from 'vue'
import { useI18n } from 'vue-i18n'
@@ -12,22 +11,17 @@ import { RouterView } from 'vue-router'
import { commands } from './bindings/tauri-plugins/window-router-link'
import { useAppRuntime } from './composables/runtime'
import { useTauriEvent } from './composables/tauri'
import { useWindowControlStore } from './stores/window-controls'
import { useWindowMode } from './stores/window-controls'
useWindowMode()
const { language, themeColorsHue, themeColorsHueDynamic, allowVisibleOnAllWorkspaces } = storeToRefs(useSettings())
const i18n = useI18n()
const windowControlStore = useWindowControlStore()
const mcpStore = useMcpStore()
const onboardingStore = useOnboardingStore()
const { shouldShowSetup } = storeToRefs(onboardingStore)
const { platform } = useAppRuntime()
const { listen } = useTauriEvent<AiriTamagotchiEvents>()
useEventListener(window, 'resize', () => {
windowControlStore.size.width = window.innerWidth
windowControlStore.size.height = window.innerHeight
})
watch(language, () => {
i18n.locale.value = language.value
})
@@ -52,6 +52,11 @@ interface Events {
}
export interface AiriTamagotchiEvents extends Events {
// from main
'tauri-main:main:window-mode:fade-on-hover': true
'tauri-main:main:window-mode:move': true
'tauri-main:main:window-mode:resize': true
// from tauri-plugin-window-pass-through-on-hover
'tauri-plugins:tauri-plugin-window-pass-through-on-hover:cursor-position': Point
'tauri-plugins:tauri-plugin-window-pass-through-on-hover:window-frame': WindowFrame
@@ -77,8 +77,7 @@ export const useShortcutsStore = defineStore('shortcuts', () => {
group: 'window',
type: 'move',
handle: async () => {
windowStore.setMode(WindowControlMode.MOVE)
windowStore.toggleControl()
windowStore.toggleMode(WindowControlMode.MOVE)
},
},
{
@@ -87,8 +86,7 @@ export const useShortcutsStore = defineStore('shortcuts', () => {
group: 'window',
type: 'resize',
handle: async () => {
windowStore.setMode(WindowControlMode.RESIZE)
windowStore.toggleControl()
windowStore.toggleMode(WindowControlMode.RESIZE)
},
},
{
@@ -1,8 +1,9 @@
import { getCurrentWindow } from '@tauri-apps/api/window'
import { useLocalStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { ref } from 'vue'
import type { AiriTamagotchiEvents } from '../composables/tauri'
import { defineStore } from 'pinia'
import { onMounted, onUnmounted, ref } from 'vue'
import { useTauriEvent } from '../composables/tauri'
import { WindowControlMode } from '../types/window-controls'
import { startClickThrough, stopClickThrough } from '../utils/windows'
@@ -10,14 +11,9 @@ export const useWindowControlStore = defineStore('windowControl', () => {
const controlMode = ref<WindowControlMode>(WindowControlMode.NONE)
const isControlActive = ref(false)
const isIgnoringMouseEvent = ref(true)
const size = useLocalStorage('window/control/size', { width: 300 * 1.5, height: 400 * 1.5 })
const position = useLocalStorage('window/control/position', { x: 0, y: 0 })
function setMode(mode: WindowControlMode) {
function toggleMode(mode: WindowControlMode) {
controlMode.value = mode
}
function toggleControl() {
isControlActive.value = !isControlActive.value
if (!isControlActive.value) {
controlMode.value = WindowControlMode.NONE
@@ -34,9 +30,46 @@ export const useWindowControlStore = defineStore('windowControl', () => {
controlMode,
isControlActive,
isIgnoringMouseEvent,
size,
position,
setMode,
toggleControl,
toggleMode,
}
})
export const useWindowMode = defineStore('window-mode', () => {
const { listen } = useTauriEvent<AiriTamagotchiEvents>()
const windowStore = useWindowControlStore()
const unlistenFuncs = ref<(() => void)[]>([])
async function setup() {
unlistenFuncs.value.push(await listen('tauri-main:main:window-mode:move', () => {
windowStore.toggleMode(WindowControlMode.MOVE)
}))
unlistenFuncs.value.push(await listen('tauri-main:main:window-mode:resize', () => {
windowStore.toggleMode(WindowControlMode.RESIZE)
}))
unlistenFuncs.value.push(await listen('tauri-main:main:window-mode:fade-on-hover', async () => {
windowStore.isIgnoringMouseEvent = !windowStore.isIgnoringMouseEvent
if (windowStore.isIgnoringMouseEvent) {
await startClickThrough()
return
}
await stopClickThrough()
}))
}
function cleanup() {
unlistenFuncs.value.forEach(unlisten => unlisten())
unlistenFuncs.value.length = 0
}
onMounted(setup)
onUnmounted(cleanup)
if (import.meta.hot) { // For better DX
import.meta.hot.on('vite:beforeUpdate', () => cleanup())
import.meta.hot.on('vite:afterUpdate', async () => await setup())
}
})