mirror of
https://github.com/ayangweb/BongoCat.git
synced 2026-03-12 17:51:48 +08:00
feat: 新增「猫咪设置 > 窗口设置 > 窗口圆角」配置项 (#644)
This commit is contained in:
@@ -84,7 +84,7 @@ useEventListener('click', (event) => {
|
||||
<ConfigProvider
|
||||
:locale="zhCN"
|
||||
:theme="{
|
||||
algorithm: generalStore.isDark ? darkAlgorithm : defaultAlgorithm,
|
||||
algorithm: generalStore.appearance.isDark ? darkAlgorithm : defaultAlgorithm,
|
||||
}"
|
||||
>
|
||||
<RouterView v-if="isRestored" />
|
||||
|
||||
@@ -35,7 +35,7 @@ const MESSAGE_KEY = 'updatable'
|
||||
|
||||
const { pause, resume } = useIntervalFn(checkUpdate, 1000 * 60 * 60 * 24)
|
||||
|
||||
watch(() => generalStore.autoCheckUpdate, (value) => {
|
||||
watch(() => generalStore.update.autoCheck, (value) => {
|
||||
pause()
|
||||
|
||||
if (!value) return
|
||||
|
||||
@@ -68,7 +68,7 @@ export function useModel() {
|
||||
|
||||
const size = await appWindow.size()
|
||||
|
||||
catStore.scale = round((size.width / width) * 100)
|
||||
catStore.window.scale = round((size.width / width) * 100)
|
||||
}
|
||||
|
||||
const handlePress = (key: string) => {
|
||||
@@ -76,7 +76,7 @@ export function useModel() {
|
||||
|
||||
if (!path) return
|
||||
|
||||
if (catStore.singleMode) {
|
||||
if (catStore.model.single) {
|
||||
const dirName = nth(path.split(sep()), -2)!
|
||||
|
||||
const filterKeys = Object.entries(modelStore.pressedKeys).filter(([, value]) => {
|
||||
@@ -127,7 +127,7 @@ export function useModel() {
|
||||
const ratio = isXAxis ? xRatio : yRatio
|
||||
let value = max - (ratio * (max - min))
|
||||
|
||||
if (isXAxis && catStore.mouseMirror) {
|
||||
if (isXAxis && catStore.model.mouseMirror) {
|
||||
value *= -1
|
||||
}
|
||||
|
||||
|
||||
@@ -14,16 +14,16 @@ export function useSharedMenu() {
|
||||
const items = options.map((item) => {
|
||||
return CheckMenuItem.new({
|
||||
text: item === 100 ? '默认' : `${item}%`,
|
||||
checked: catStore.scale === item,
|
||||
checked: catStore.window.scale === item,
|
||||
action: () => {
|
||||
catStore.scale = item
|
||||
catStore.window.scale = item
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
if (!options.includes(catStore.scale)) {
|
||||
if (!options.includes(catStore.window.scale)) {
|
||||
items.unshift(CheckMenuItem.new({
|
||||
text: `${catStore.scale}%`,
|
||||
text: `${catStore.window.scale}%`,
|
||||
checked: true,
|
||||
enabled: false,
|
||||
}))
|
||||
@@ -38,16 +38,16 @@ export function useSharedMenu() {
|
||||
const items = options.map((item) => {
|
||||
return CheckMenuItem.new({
|
||||
text: `${item}%`,
|
||||
checked: catStore.opacity === item,
|
||||
checked: catStore.window.opacity === item,
|
||||
action: () => {
|
||||
catStore.opacity = item
|
||||
catStore.window.opacity = item
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
if (!options.includes(catStore.opacity)) {
|
||||
if (!options.includes(catStore.window.opacity)) {
|
||||
items.unshift(CheckMenuItem.new({
|
||||
text: `${catStore.opacity}%`,
|
||||
text: `${catStore.window.opacity}%`,
|
||||
checked: true,
|
||||
enabled: false,
|
||||
}))
|
||||
@@ -64,17 +64,17 @@ export function useSharedMenu() {
|
||||
action: () => showWindow('preference'),
|
||||
}),
|
||||
MenuItem.new({
|
||||
text: catStore.visible ? '隐藏猫咪' : '显示猫咪',
|
||||
text: catStore.window.visible ? '隐藏猫咪' : '显示猫咪',
|
||||
action: () => {
|
||||
catStore.visible = !catStore.visible
|
||||
catStore.window.visible = !catStore.window.visible
|
||||
},
|
||||
}),
|
||||
PredefinedMenuItem.new({ item: 'Separator' }),
|
||||
CheckMenuItem.new({
|
||||
text: '窗口穿透',
|
||||
checked: catStore.penetrable,
|
||||
checked: catStore.window.passThrough,
|
||||
action: () => {
|
||||
catStore.penetrable = !catStore.penetrable
|
||||
catStore.window.passThrough = !catStore.window.passThrough
|
||||
},
|
||||
}),
|
||||
Submenu.new({
|
||||
|
||||
@@ -24,11 +24,11 @@ export function useTray() {
|
||||
const catStore = useCatStore()
|
||||
const { getSharedMenu } = useSharedMenu()
|
||||
|
||||
watch([() => catStore.visible, () => catStore.penetrable], () => {
|
||||
watch([() => catStore.window.visible, () => catStore.window.passThrough], () => {
|
||||
updateTrayMenu()
|
||||
})
|
||||
|
||||
watchDebounced([() => catStore.scale, () => catStore.opacity], () => {
|
||||
watchDebounced([() => catStore.window.scale, () => catStore.window.opacity], () => {
|
||||
updateTrayMenu()
|
||||
}, { debounce: 200 })
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ watch(() => modelStore.currentModel, async (model) => {
|
||||
}
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
watch([() => catStore.scale, modelSize], async ([scale, modelSize]) => {
|
||||
watch([() => catStore.window.scale, modelSize], async ([scale, modelSize]) => {
|
||||
if (!modelSize) return
|
||||
|
||||
const { width, height } = modelSize
|
||||
@@ -103,17 +103,17 @@ watch([modelStore.pressedKeys, stickActive], ([keys, stickActive]) => {
|
||||
handleKeyChange(false, stickActive.right || hasRight)
|
||||
}, { deep: true })
|
||||
|
||||
watch(() => catStore.visible, async (value) => {
|
||||
watch(() => catStore.window.visible, async (value) => {
|
||||
value ? showWindow() : hideWindow()
|
||||
})
|
||||
|
||||
watch(() => catStore.penetrable, (value) => {
|
||||
watch(() => catStore.window.passThrough, (value) => {
|
||||
appWindow.setIgnoreCursorEvents(value)
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => catStore.alwaysOnTop, setAlwaysOnTop, { immediate: true })
|
||||
watch(() => catStore.window.alwaysOnTop, setAlwaysOnTop, { immediate: true })
|
||||
|
||||
watch(() => generalStore.taskbarVisibility, setTaskbarVisibility, { immediate: true })
|
||||
watch(() => generalStore.app.taskbarVisible, setTaskbarVisibility, { immediate: true })
|
||||
|
||||
function handleMouseDown() {
|
||||
appWindow.startDragging()
|
||||
@@ -137,17 +137,20 @@ function handleMouseMove(event: MouseEvent) {
|
||||
if (buttons !== 2 || !shiftKey) return
|
||||
|
||||
const delta = (movementX + movementY) * 0.5
|
||||
const nextScale = Math.max(10, Math.min(catStore.scale + delta, 500))
|
||||
const nextScale = Math.max(10, Math.min(catStore.window.scale + delta, 500))
|
||||
|
||||
catStore.scale = round(nextScale)
|
||||
catStore.window.scale = round(nextScale)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="relative size-screen overflow-hidden children:(absolute size-full)"
|
||||
:class="{ '-scale-x-100': catStore.mirrorMode }"
|
||||
:style="{ opacity: catStore.opacity / 100 }"
|
||||
:class="{ '-scale-x-100': catStore.model.mirror }"
|
||||
:style="{
|
||||
opacity: catStore.window.opacity / 100,
|
||||
borderRadius: `${catStore.window.radius}%`,
|
||||
}"
|
||||
@contextmenu="handleContextmenu"
|
||||
@mousedown="handleMouseDown"
|
||||
@mousemove="handleMouseMove"
|
||||
|
||||
@@ -14,21 +14,21 @@ const catStore = useCatStore()
|
||||
description="启用后,模型将水平镜像翻转。"
|
||||
title="镜像模式"
|
||||
>
|
||||
<Switch v-model:checked="catStore.mirrorMode" />
|
||||
<Switch v-model:checked="catStore.model.mirror" />
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
description="启用后,每只手只显示最后按下的一个按键。"
|
||||
title="单键模式"
|
||||
>
|
||||
<Switch v-model:checked="catStore.singleMode" />
|
||||
<Switch v-model:checked="catStore.model.single" />
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
description="启用后,鼠标将镜像跟随手部移动。"
|
||||
title="鼠标镜像"
|
||||
>
|
||||
<Switch v-model:checked="catStore.mouseMirror" />
|
||||
<Switch v-model:checked="catStore.model.mouseMirror" />
|
||||
</ProListItem>
|
||||
</ProList>
|
||||
|
||||
@@ -37,14 +37,14 @@ const catStore = useCatStore()
|
||||
description="启用后,窗口不影响对其他应用程序的操作。"
|
||||
title="窗口穿透"
|
||||
>
|
||||
<Switch v-model:checked="catStore.penetrable" />
|
||||
<Switch v-model:checked="catStore.window.passThrough" />
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
description="启用后,窗口始终显示在其他应用程序上方。"
|
||||
title="窗口置顶"
|
||||
>
|
||||
<Switch v-model:checked="catStore.alwaysOnTop" />
|
||||
<Switch v-model:checked="catStore.window.alwaysOnTop" />
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
@@ -52,14 +52,20 @@ const catStore = useCatStore()
|
||||
title="窗口尺寸"
|
||||
>
|
||||
<InputNumber
|
||||
v-model:value="catStore.scale"
|
||||
v-model:value="catStore.window.scale"
|
||||
addon-after="%"
|
||||
class="w-28"
|
||||
:min="1"
|
||||
>
|
||||
<template #addonAfter>
|
||||
%
|
||||
</template>
|
||||
</InputNumber>
|
||||
/>
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem title="窗口圆角">
|
||||
<InputNumber
|
||||
v-model:value="catStore.window.radius"
|
||||
addon-after="%"
|
||||
class="w-28"
|
||||
:min="0"
|
||||
/>
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
@@ -67,7 +73,7 @@ const catStore = useCatStore()
|
||||
vertical
|
||||
>
|
||||
<Slider
|
||||
v-model:value="catStore.opacity"
|
||||
v-model:value="catStore.window.opacity"
|
||||
class="m-0!"
|
||||
:max="100"
|
||||
:min="10"
|
||||
|
||||
@@ -11,23 +11,23 @@ const appWindow = getCurrentWebviewWindow()
|
||||
|
||||
onMounted(() => {
|
||||
appWindow.onThemeChanged(async ({ payload }) => {
|
||||
if (generalStore.theme !== 'auto') return
|
||||
if (generalStore.appearance.theme !== 'auto') return
|
||||
|
||||
generalStore.isDark = payload === 'dark'
|
||||
generalStore.appearance.isDark = payload === 'dark'
|
||||
})
|
||||
})
|
||||
|
||||
watch(() => generalStore.theme, async (value) => {
|
||||
watch(() => generalStore.appearance.theme, async (value) => {
|
||||
let nextTheme = value === 'auto' ? null : value
|
||||
|
||||
await appWindow.setTheme(nextTheme)
|
||||
|
||||
nextTheme = nextTheme ?? (await appWindow.theme())
|
||||
|
||||
generalStore.isDark = nextTheme === 'dark'
|
||||
generalStore.appearance.isDark = nextTheme === 'dark'
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => generalStore.isDark, (value) => {
|
||||
watch(() => generalStore.appearance.isDark, (value) => {
|
||||
if (value) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
@@ -38,7 +38,7 @@ watch(() => generalStore.isDark, (value) => {
|
||||
|
||||
<template>
|
||||
<ProListItem title="主题模式">
|
||||
<Select v-model:value="generalStore.theme">
|
||||
<Select v-model:value="generalStore.appearance.theme">
|
||||
<SelectOption value="auto">
|
||||
跟随系统
|
||||
</SelectOption>
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useGeneralStore } from '@/stores/general'
|
||||
|
||||
const generalStore = useGeneralStore()
|
||||
|
||||
watch(() => generalStore.autostart, async (value) => {
|
||||
watch(() => generalStore.app.autostart, async (value) => {
|
||||
const enabled = await isEnabled()
|
||||
|
||||
if (value && !enabled) {
|
||||
@@ -30,14 +30,14 @@ watch(() => generalStore.autostart, async (value) => {
|
||||
|
||||
<ProList title="应用设置">
|
||||
<ProListItem title="开机自启动">
|
||||
<Switch v-model:checked="generalStore.autostart" />
|
||||
<Switch v-model:checked="generalStore.app.autostart" />
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
description="启用后,即可通过 OBS Studio 捕获窗口。"
|
||||
title="显示任务栏图标"
|
||||
>
|
||||
<Switch v-model:checked="generalStore.taskbarVisibility" />
|
||||
<Switch v-model:checked="generalStore.app.taskbarVisible" />
|
||||
</ProListItem>
|
||||
</ProList>
|
||||
|
||||
@@ -47,7 +47,7 @@ watch(() => generalStore.autostart, async (value) => {
|
||||
|
||||
<ProList title="更新设置">
|
||||
<ProListItem title="自动检查更新">
|
||||
<Switch v-model:checked="generalStore.autoCheckUpdate" />
|
||||
<Switch v-model:checked="generalStore.update.autoCheck" />
|
||||
</ProListItem>
|
||||
</ProList>
|
||||
</template>
|
||||
|
||||
@@ -13,7 +13,7 @@ const { visibleCat, visiblePreference, mirrorMode, penetrable, alwaysOnTop } = s
|
||||
const catStore = useCatStore()
|
||||
|
||||
useTauriShortcut(visibleCat, () => {
|
||||
catStore.visible = !catStore.visible
|
||||
catStore.window.visible = !catStore.window.visible
|
||||
})
|
||||
|
||||
useTauriShortcut(visiblePreference, () => {
|
||||
@@ -21,15 +21,15 @@ useTauriShortcut(visiblePreference, () => {
|
||||
})
|
||||
|
||||
useTauriShortcut(mirrorMode, () => {
|
||||
catStore.mirrorMode = !catStore.mirrorMode
|
||||
catStore.model.mirror = !catStore.model.mirror
|
||||
})
|
||||
|
||||
useTauriShortcut(penetrable, () => {
|
||||
catStore.penetrable = !catStore.penetrable
|
||||
catStore.window.passThrough = !catStore.window.passThrough
|
||||
})
|
||||
|
||||
useTauriShortcut(alwaysOnTop, () => {
|
||||
catStore.alwaysOnTop = !catStore.alwaysOnTop
|
||||
catStore.window.alwaysOnTop = !catStore.window.alwaysOnTop
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,29 +1,76 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
export interface CatStore {
|
||||
model: {
|
||||
mirror: boolean
|
||||
single: boolean
|
||||
mouseMirror: boolean
|
||||
}
|
||||
window: {
|
||||
visible: boolean
|
||||
passThrough: boolean
|
||||
alwaysOnTop: boolean
|
||||
scale: number
|
||||
opacity: number
|
||||
radius: number
|
||||
}
|
||||
}
|
||||
|
||||
export const useCatStore = defineStore('cat', () => {
|
||||
const visible = ref(false)
|
||||
/* ------------ 废弃字段(后续删除) ------------ */
|
||||
|
||||
/** @deprecated 请使用 `model.mirror` */
|
||||
const mirrorMode = ref(false)
|
||||
|
||||
/** @deprecated 请使用 `model.single` */
|
||||
const singleMode = ref(false)
|
||||
|
||||
/** @deprecated 请使用 `model.mouseMirror` */
|
||||
const mouseMirror = ref(false)
|
||||
|
||||
/** @deprecated 请使用 `window.passThrough` */
|
||||
const penetrable = ref(false)
|
||||
|
||||
/** @deprecated 请使用 `window.alwaysOnTop` */
|
||||
const alwaysOnTop = ref(true)
|
||||
|
||||
/** @deprecated 请使用 `window.scale` */
|
||||
const scale = ref(100)
|
||||
|
||||
/** @deprecated 请使用 `window.opacity` */
|
||||
const opacity = ref(100)
|
||||
|
||||
const model = reactive<CatStore['model']>({
|
||||
mirror: false,
|
||||
single: false,
|
||||
mouseMirror: false,
|
||||
})
|
||||
|
||||
const window = reactive<CatStore['window']>({
|
||||
visible: true,
|
||||
passThrough: false,
|
||||
alwaysOnTop: false,
|
||||
scale: 100,
|
||||
opacity: 100,
|
||||
radius: 0,
|
||||
})
|
||||
|
||||
const init = () => {
|
||||
visible.value = true
|
||||
model.mirror = mirrorMode.value
|
||||
model.single = singleMode.value
|
||||
model.mouseMirror = mouseMirror.value
|
||||
|
||||
window.visible = true
|
||||
window.passThrough = penetrable.value
|
||||
window.alwaysOnTop = alwaysOnTop.value
|
||||
window.scale = scale.value
|
||||
window.opacity = opacity.value
|
||||
}
|
||||
|
||||
return {
|
||||
visible,
|
||||
mirrorMode,
|
||||
singleMode,
|
||||
mouseMirror,
|
||||
penetrable,
|
||||
alwaysOnTop,
|
||||
scale,
|
||||
opacity,
|
||||
model,
|
||||
window,
|
||||
init,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,20 +1,68 @@
|
||||
import type { Theme } from '@tauri-apps/api/window'
|
||||
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
export interface GeneralStore {
|
||||
app: {
|
||||
autostart: boolean
|
||||
taskbarVisible: boolean
|
||||
}
|
||||
appearance: {
|
||||
theme: 'auto' | Theme
|
||||
isDark: boolean
|
||||
}
|
||||
update: {
|
||||
autoCheck: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export const useGeneralStore = defineStore('general', () => {
|
||||
/* ------------ 废弃字段(后续删除) ------------ */
|
||||
|
||||
/** @deprecated 请使用 `update.autoCheck` */
|
||||
const autoCheckUpdate = ref(false)
|
||||
|
||||
/** @deprecated 请使用 `app.autostart` */
|
||||
const autostart = ref(false)
|
||||
|
||||
/** @deprecated 请使用 `app.taskbarVisible` */
|
||||
const taskbarVisibility = ref(false)
|
||||
|
||||
/** @deprecated 请使用 `appearance.theme` */
|
||||
const theme = ref<'auto' | Theme>('auto')
|
||||
|
||||
/** @deprecated 请使用 `appearance.isDark` */
|
||||
const isDark = ref(false)
|
||||
|
||||
const app = reactive<GeneralStore['app']>({
|
||||
autostart: false,
|
||||
taskbarVisible: false,
|
||||
})
|
||||
|
||||
const appearance = reactive<GeneralStore['appearance']>({
|
||||
theme: 'auto',
|
||||
isDark: false,
|
||||
})
|
||||
|
||||
const update = reactive<GeneralStore['update']>({
|
||||
autoCheck: false,
|
||||
})
|
||||
|
||||
const init = () => {
|
||||
app.autostart = autostart.value
|
||||
app.taskbarVisible = taskbarVisibility.value
|
||||
|
||||
appearance.theme = theme.value
|
||||
appearance.isDark = isDark.value
|
||||
|
||||
update.autoCheck = autoCheckUpdate.value
|
||||
}
|
||||
|
||||
return {
|
||||
autoCheckUpdate,
|
||||
autostart,
|
||||
taskbarVisibility,
|
||||
theme,
|
||||
isDark,
|
||||
app,
|
||||
appearance,
|
||||
update,
|
||||
init,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user