Skip to content

Commit 48e0021

Browse files
authored
feat: 新增「猫咪设置 > 窗口设置 > 保持在屏幕内」配置项 (#904)
1 parent f0c1250 commit 48e0021

12 files changed

Lines changed: 39 additions & 4 deletions

File tree

src/composables/useSharedMenu.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { CheckMenuItem, MenuItem, PredefinedMenuItem, Submenu } from '@tauri-app
22
import { range } from 'es-toolkit'
33
import { useI18n } from 'vue-i18n'
44

5+
import { WINDOW_LABEL } from '@/constants'
56
import { showWindow } from '@/plugins/window'
67
import { useCatStore } from '@/stores/cat'
78
import { isMac } from '@/utils/platform'
@@ -63,7 +64,7 @@ export function useSharedMenu() {
6364
MenuItem.new({
6465
text: t('composables.useSharedMenu.labels.preference'),
6566
accelerator: isMac ? 'Cmd+,' : '',
66-
action: () => showWindow('preference'),
67+
action: () => showWindow(WINDOW_LABEL.PREFERENCE),
6768
}),
6869
MenuItem.new({
6970
text: catStore.window.visible ? t('composables.useSharedMenu.labels.hideCat') : t('composables.useSharedMenu.labels.showCat'),

src/composables/useWindowState.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
55
import { availableMonitors } from '@tauri-apps/api/window'
66
import { useDebounceFn } from '@vueuse/core'
77
import { isNumber } from 'es-toolkit/compat'
8-
import { onMounted, ref } from 'vue'
8+
import { onMounted, ref, watch } from 'vue'
99

10+
import { WINDOW_LABEL } from '@/constants'
1011
import { useAppStore } from '@/stores/app'
12+
import { useCatStore } from '@/stores/cat'
1113
import { getCursorMonitor } from '@/utils/monitor'
1214

1315
export type WindowState = Record<string, Partial<PhysicalPosition & PhysicalSize> | undefined>
@@ -17,6 +19,7 @@ const { label } = appWindow
1719

1820
export function useWindowState() {
1921
const appStore = useAppStore()
22+
const catStore = useCatStore()
2023
const isRestored = ref(false)
2124

2225
onMounted(() => {
@@ -28,6 +31,8 @@ export function useWindowState() {
2831
})
2932

3033
const clampToMonitor = useDebounceFn(async () => {
34+
if (label !== WINDOW_LABEL.MAIN || !catStore.window.keepInScreen) return
35+
3136
const monitor = await getCursorMonitor()
3237

3338
if (!monitor) return
@@ -49,6 +54,8 @@ export function useWindowState() {
4954
return appWindow.setPosition(new PhysicalPosition(clampedX, clampedY))
5055
}, 500)
5156

57+
watch(() => catStore.window.keepInScreen, clampToMonitor)
58+
5259
const onChange = async (event: Event<PhysicalPosition | PhysicalSize>) => {
5360
const minimized = await appWindow.isMinimized()
5461

src/constants/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,8 @@ export const LANGUAGE = {
2626
VI_VN: 'vi-VN',
2727
PT_BR: 'pt-BR',
2828
} as const
29+
30+
export const WINDOW_LABEL = {
31+
MAIN: 'main',
32+
PREFERENCE: 'preference',
33+
} as const

src/locales/en-US.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"windowSettings": "Window Settings",
1818
"passThrough": "Pass Through",
1919
"alwaysOnTop": "Always on Top",
20+
"keepInScreen": "Keep on Screen",
2021
"windowSize": "Window Size",
2122
"windowRadius": "Window Radius",
2223
"opacity": "Opacity",
@@ -31,6 +32,7 @@
3132
"motionSound": "When enabled, the model will play corresponding sound effects when performing actions (if they exist).",
3233
"passThrough": "When enabled, clicks pass through the window without affecting it.",
3334
"alwaysOnTop": "When enabled, the window stays above all other windows.",
35+
"keepInScreen": "When enabled, the window automatically stays within the screen boundaries.",
3436
"windowSize": "Move mouse to window edge, or hold Shift and right-drag to resize.",
3537
"autoReleaseDelay": "On Windows, some system keys cannot capture release events and will auto-release after timeout.",
3638
"hideOnHover": "When enabled, the window hides when mouse hovers over it."

src/locales/pt-BR.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"windowSettings": "Configurações da Janela",
1818
"passThrough": "Janela Transparente",
1919
"alwaysOnTop": "Sempre no Topo",
20+
"keepInScreen": "Manter na Tela",
2021
"windowSize": "Tamanho da Janela",
2122
"windowRadius": "Raio da Janela",
2223
"opacity": "Opacidade",
@@ -31,6 +32,7 @@
3132
"motionSound": "Quando ativado, o modelo reproduzirá efeitos sonoros correspondentes ao executar ações (se existirem).",
3233
"passThrough": "Quando ativado, a janela não afetará operações em outros aplicativos.",
3334
"alwaysOnTop": "Quando ativado, a janela sempre ficará acima de outros aplicativos.",
35+
"keepInScreen": "Quando ativado, a janela permanece automaticamente dentro dos limites da tela.",
3436
"windowSize": "Mova o mouse para a borda da janela ou segure Shift e arraste com o botão direito para redimensionar.",
3537
"autoReleaseDelay": "Devido ao Windows não capturar eventos de liberação de certas teclas de nível do sistema, elas serão automaticamente tratadas como liberadas após um tempo limite.",
3638
"hideOnHover": "Quando ativado, a janela será ocultada quando o mouse passar sobre ela."

src/locales/vi-VN.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"windowSettings": "Cài đặt Cửa sổ",
1818
"passThrough": "Click xuyên",
1919
"alwaysOnTop": "Luôn trên cùng",
20+
"keepInScreen": "Giữ trong màn hình",
2021
"windowSize": "Kích thước",
2122
"windowRadius": "Độ bo tròn cửa sổ",
2223
"opacity": "Độ mờ",
@@ -31,6 +32,7 @@
3132
"motionSound": "Khi bật, mô hình sẽ phát các âm thanh tương ứng khi thực hiện hành động (nếu tồn tại).",
3233
"passThrough": "Bật để cửa sổ không ảnh hưởng đến thao tác trên ứng dụng khác.",
3334
"alwaysOnTop": "Bật để cửa sổ luôn nằm trên ứng dụng khác.",
35+
"keepInScreen": "Khi bật, cửa sổ sẽ tự động giữ trong ranh giới màn hình.",
3436
"windowSize": "Di chuyển chuột đến mép cửa sổ hoặc giữ Shift và kéo chuột phải để thay đổi kích thước.",
3537
"autoReleaseDelay": "Do Windows không bắt được sự kiện nhả của một số phím hệ thống, các phím đó sẽ được tự động xem như đã nhả sau khi hết thời gian chờ.",
3638
"hideOnHover": "Khi bật, cửa sổ sẽ ẩn khi chuột di chuyển vào."

src/locales/zh-CN.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"windowSettings": "窗口设置",
1818
"passThrough": "窗口穿透",
1919
"alwaysOnTop": "窗口置顶",
20+
"keepInScreen": "保持在屏幕内",
2021
"windowSize": "窗口尺寸",
2122
"windowRadius": "窗口圆角",
2223
"opacity": "不透明度",
@@ -31,6 +32,7 @@
3132
"motionSound": "启用后,模型执行动作时会播放对应音效(如果存在)。",
3233
"passThrough": "启用后,窗口不影响对其他应用程序的操作。",
3334
"alwaysOnTop": "启用后,窗口始终显示在其他应用程序上方。",
35+
"keepInScreen": "启用后,窗口会自动调整位置,防止超出屏幕边界。",
3436
"windowSize": "将鼠标移至窗口边缘,或按住 Shift 并右键拖动,也可以调整窗口大小。",
3537
"autoReleaseDelay": "由于 Windows 下部分系统级按键无法捕获释放事件,超时后将自动视为已释放。",
3638
"hideOnHover": "启用后,鼠标悬停在窗口上时,窗口会隐藏。"

src/locales/zh-TW.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"windowSettings": "視窗設定",
1818
"passThrough": "視窗穿透",
1919
"alwaysOnTop": "視窗置頂",
20+
"keepInScreen": "保持在螢幕內",
2021
"windowSize": "視窗尺寸",
2122
"windowRadius": "視窗圓角",
2223
"opacity": "不透明度",
@@ -31,6 +32,7 @@
3132
"motionSound": "啟用後,模型執行動作時會播放對應音效(如果存在)。",
3233
"passThrough": "啟用後,視窗不影響對其他應用程式的操作。",
3334
"alwaysOnTop": "啟用後,視窗始終顯示在其他應用程式上方。",
35+
"keepInScreen": "啟用後,視窗會自動調整位置,防止超出螢幕邊界。",
3436
"windowSize": "將滑鼠游標移至視窗邊緣,或按住 Shift 並右鍵拖曳,也可以調整視窗大小。",
3537
"autoReleaseDelay": "由於 Windows 下部份系統級按鍵無法擷取釋放事件,超時後將自動視為已釋放。",
3638
"hideOnHover": "啟用後,滑鼠游標懸停在視窗上時,視窗會隱藏。"

src/pages/preference/components/cat/index.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ const catStore = useCatStore()
7474
<Switch v-model:checked="catStore.window.hideOnHover" />
7575
</ProListItem>
7676

77+
<ProListItem
78+
:description="$t('pages.preference.cat.hints.keepInScreen')"
79+
:title="$t('pages.preference.cat.labels.keepInScreen')"
80+
>
81+
<Switch v-model:checked="catStore.window.keepInScreen" />
82+
</ProListItem>
83+
7784
<ProListItem
7885
:description="$t('pages.preference.cat.hints.windowSize')"
7986
:title="$t('pages.preference.cat.labels.windowSize')"

src/pages/preference/components/shortcut/index.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import ProList from '@/components/pro-list/index.vue'
55
import ProListItem from '@/components/pro-list-item/index.vue'
66
import Shortcut from '@/components/shortcut/index.vue'
77
import { useKeyPress } from '@/composables/useKeyPress'
8+
import { WINDOW_LABEL } from '@/constants'
89
import { toggleWindowVisible } from '@/plugins/window'
910
import { useCatStore } from '@/stores/cat'
1011
import { useShortcutStore } from '@/stores/shortcut.ts'
@@ -18,7 +19,7 @@ useKeyPress(visibleCat, () => {
1819
})
1920
2021
useKeyPress(visiblePreference, () => {
21-
toggleWindowVisible('preference')
22+
toggleWindowVisible(WINDOW_LABEL.PREFERENCE)
2223
})
2324
2425
useKeyPress(mirrorMode, () => {

0 commit comments

Comments
 (0)