mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
feat(uiMode): 添加UI模式手动切换功能
This commit is contained in:
@@ -12,6 +12,16 @@ const globalPwaStatus = ref<{
|
|||||||
const globalLoading = ref(false)
|
const globalLoading = ref(false)
|
||||||
let initPromise: Promise<void> | null = null
|
let initPromise: Promise<void> | null = null
|
||||||
|
|
||||||
|
// UI模式设置
|
||||||
|
export type UIMode = 'auto' | 'desktop' | 'app'
|
||||||
|
const uiMode = ref<UIMode>((localStorage.getItem('ui-mode') as UIMode) || 'auto')
|
||||||
|
|
||||||
|
// 设置UI模式
|
||||||
|
function setUIMode(mode: UIMode) {
|
||||||
|
uiMode.value = mode
|
||||||
|
localStorage.setItem('ui-mode', mode)
|
||||||
|
}
|
||||||
|
|
||||||
// 全局初始化函数
|
// 全局初始化函数
|
||||||
async function initializePWAGlobally() {
|
async function initializePWAGlobally() {
|
||||||
if (initPromise) return initPromise
|
if (initPromise) return initPromise
|
||||||
@@ -50,6 +60,8 @@ export function usePWA() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const appMode = computed(() => {
|
const appMode = computed(() => {
|
||||||
|
if (uiMode.value === 'app') return true
|
||||||
|
if (uiMode.value === 'desktop') return false
|
||||||
return pwaMode.value && display.mdAndDown.value
|
return pwaMode.value && display.mdAndDown.value
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -70,6 +82,8 @@ export function usePWA() {
|
|||||||
pwaMode,
|
pwaMode,
|
||||||
appMode,
|
appMode,
|
||||||
pwaStatus,
|
pwaStatus,
|
||||||
|
uiMode,
|
||||||
|
setUIMode,
|
||||||
loading: globalLoading,
|
loading: globalLoading,
|
||||||
initializePWA: initializePWAGlobally,
|
initializePWA: initializePWAGlobally,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,16 +236,15 @@ export function usePullDownGesture(options: PullDownOptions = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PWA状态确定后,一次性决定是否添加事件监听器
|
// 监听 appMode 变化动态添加/移除事件监听器
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 等待PWA检测完成后添加事件监听器
|
watch(
|
||||||
const stopWatcher = watch(
|
|
||||||
appMode,
|
appMode,
|
||||||
newValue => {
|
newValue => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
addEventListeners()
|
addEventListeners()
|
||||||
// PWA状态确定后停止监听
|
} else {
|
||||||
stopWatcher()
|
removeEventListeners()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { saveLocalTheme } from '@/@core/utils/theme'
|
|||||||
import type { ThemeSwitcherTheme } from '@layouts/types'
|
import type { ThemeSwitcherTheme } from '@layouts/types'
|
||||||
import { useConfirm } from '@/composables/useConfirm'
|
import { useConfirm } from '@/composables/useConfirm'
|
||||||
import { themeManager } from '@/utils/themeManager'
|
import { themeManager } from '@/utils/themeManager'
|
||||||
|
import { usePWA, type UIMode } from '@/composables/usePWA'
|
||||||
|
|
||||||
// 认证 Store
|
// 认证 Store
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
@@ -27,6 +28,8 @@ const globalSettingsStore = useGlobalSettingsStore()
|
|||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
// 显示器
|
// 显示器
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
|
// PWA
|
||||||
|
const { uiMode, setUIMode } = usePWA()
|
||||||
|
|
||||||
// 提示框
|
// 提示框
|
||||||
const $toast = useToast()
|
const $toast = useToast()
|
||||||
@@ -40,6 +43,9 @@ const siteAuthDialog = ref(false)
|
|||||||
// 自定义CSS弹窗
|
// 自定义CSS弹窗
|
||||||
const cssDialog = ref(false)
|
const cssDialog = ref(false)
|
||||||
|
|
||||||
|
// UI模式菜单是否显示
|
||||||
|
const showUIModeMenu = ref(false)
|
||||||
|
|
||||||
// 主题菜单是否显示
|
// 主题菜单是否显示
|
||||||
const showThemeMenu = ref(false)
|
const showThemeMenu = ref(false)
|
||||||
|
|
||||||
@@ -233,6 +239,39 @@ const isAdvancedMode = computed(() => {
|
|||||||
return globalSettingsStore.get('ADVANCED_MODE') !== false
|
return globalSettingsStore.get('ADVANCED_MODE') !== false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// UI模式相关
|
||||||
|
const uiModes = computed(() => [
|
||||||
|
{
|
||||||
|
name: 'auto',
|
||||||
|
title: t('theme.autoUI'),
|
||||||
|
icon: 'mdi-devices',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'desktop',
|
||||||
|
title: t('pwa.platforms.desktop'),
|
||||||
|
icon: 'mdi-monitor',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'app',
|
||||||
|
title: t('pwa.platforms.mobile'),
|
||||||
|
icon: 'mdi-cellphone',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
// 切换UI模式
|
||||||
|
function changeUIMode(mode: UIMode) {
|
||||||
|
setUIMode(mode)
|
||||||
|
showUIModeMenu.value = false
|
||||||
|
// 刷新页面以应用更改
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前UI模式图标
|
||||||
|
const getUIModeIcon = computed(() => {
|
||||||
|
const mode = uiModes.value.find(m => m.name === uiMode.value)
|
||||||
|
return mode?.icon || 'mdi-devices'
|
||||||
|
})
|
||||||
|
|
||||||
// 主题相关功能
|
// 主题相关功能
|
||||||
const { name: themeName, global: globalTheme } = useTheme()
|
const { name: themeName, global: globalTheme } = useTheme()
|
||||||
const savedTheme = ref(localStorage.getItem('theme') ?? themeName)
|
const savedTheme = ref(localStorage.getItem('theme') ?? themeName)
|
||||||
@@ -546,6 +585,41 @@ onUnmounted(() => {
|
|||||||
<VListItemTitle>{{ t('user.siteAuth') }}</VListItemTitle>
|
<VListItemTitle>{{ t('user.siteAuth') }}</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
|
||||||
|
<!-- 👉 UI模式设置 - 使用嵌套菜单 -->
|
||||||
|
<VMenu location="end" offset-x min-width="200" v-model="showUIModeMenu" :close-on-content-click="true">
|
||||||
|
<template v-slot:activator="{ props: menuProps }">
|
||||||
|
<VListItem v-bind="menuProps" class="mb-1 rounded-lg" hover>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon :icon="getUIModeIcon" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle>{{ t('common.uiMode') }}</VListItemTitle>
|
||||||
|
<VListItemSubtitle>
|
||||||
|
{{ uiModes.find(m => m.name === uiMode)?.title || t('theme.autoUI') }}
|
||||||
|
</VListItemSubtitle>
|
||||||
|
<template #append>
|
||||||
|
<VIcon icon="mdi-chevron-right" size="small" />
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
</template>
|
||||||
|
<VList>
|
||||||
|
<VListItem
|
||||||
|
v-for="mode in uiModes"
|
||||||
|
:key="mode.name"
|
||||||
|
@click="changeUIMode(mode.name as UIMode)"
|
||||||
|
:active="uiMode === mode.name"
|
||||||
|
class="mb-1"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon :icon="mode.icon" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle>{{ mode.title }}</VListItemTitle>
|
||||||
|
<template #append v-if="uiMode === mode.name">
|
||||||
|
<VIcon icon="mdi-check" color="primary" size="small" />
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
|
||||||
<!-- 👉 主题设置 - 使用嵌套菜单 -->
|
<!-- 👉 主题设置 - 使用嵌套菜单 -->
|
||||||
<VMenu location="end" offset-x min-width="200" v-model="showThemeMenu" :close-on-content-click="true">
|
<VMenu location="end" offset-x min-width="200" v-model="showThemeMenu" :close-on-content-click="true">
|
||||||
<template v-slot:activator="{ props: menuProps }">
|
<template v-slot:activator="{ props: menuProps }">
|
||||||
@@ -553,9 +627,10 @@ onUnmounted(() => {
|
|||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VIcon :icon="getThemeIcon" />
|
<VIcon :icon="getThemeIcon" />
|
||||||
</template>
|
</template>
|
||||||
<VListItemTitle>
|
<VListItemTitle>{{ t('common.theme') }}</VListItemTitle>
|
||||||
{{ themes.find(t => t.name === currentThemeName)?.title || t('common.theme') }}
|
<VListItemSubtitle>
|
||||||
</VListItemTitle>
|
{{ themes.find(t => t.name === currentThemeName)?.title || t('theme.auto') }}
|
||||||
|
</VListItemSubtitle>
|
||||||
<template #append>
|
<template #append>
|
||||||
<VIcon icon="mdi-chevron-right" size="small" />
|
<VIcon icon="mdi-chevron-right" size="small" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export default {
|
|||||||
saving: 'Saving',
|
saving: 'Saving',
|
||||||
reset: 'Reset',
|
reset: 'Reset',
|
||||||
theme: 'Theme',
|
theme: 'Theme',
|
||||||
|
uiMode: 'UI Layout',
|
||||||
language: 'Language',
|
language: 'Language',
|
||||||
pleaseWait: 'Please wait...',
|
pleaseWait: 'Please wait...',
|
||||||
viewDetails: 'View Details',
|
viewDetails: 'View Details',
|
||||||
@@ -131,6 +132,7 @@ export default {
|
|||||||
light: 'Light',
|
light: 'Light',
|
||||||
dark: 'Dark',
|
dark: 'Dark',
|
||||||
auto: 'Follow System',
|
auto: 'Follow System',
|
||||||
|
autoUI: 'Auto Layout',
|
||||||
transparent: 'Transparent',
|
transparent: 'Transparent',
|
||||||
purple: 'Purple',
|
purple: 'Purple',
|
||||||
custom: 'Custom Style',
|
custom: 'Custom Style',
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export default {
|
|||||||
saving: '保存中',
|
saving: '保存中',
|
||||||
reset: '重置',
|
reset: '重置',
|
||||||
theme: '主题',
|
theme: '主题',
|
||||||
|
uiMode: '界面布局',
|
||||||
language: '语言',
|
language: '语言',
|
||||||
pleaseWait: '请稍候...',
|
pleaseWait: '请稍候...',
|
||||||
viewDetails: '查看详情',
|
viewDetails: '查看详情',
|
||||||
@@ -131,6 +132,7 @@ export default {
|
|||||||
light: '浅色',
|
light: '浅色',
|
||||||
dark: '深色',
|
dark: '深色',
|
||||||
auto: '跟随系统',
|
auto: '跟随系统',
|
||||||
|
autoUI: '自动布局',
|
||||||
transparent: '透明',
|
transparent: '透明',
|
||||||
purple: '幻紫',
|
purple: '幻紫',
|
||||||
custom: '附加样式',
|
custom: '附加样式',
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export default {
|
|||||||
saving: '保存中',
|
saving: '保存中',
|
||||||
reset: '重置',
|
reset: '重置',
|
||||||
theme: '主題',
|
theme: '主題',
|
||||||
|
uiMode: '界面佈局',
|
||||||
language: '語言',
|
language: '語言',
|
||||||
pleaseWait: '請稍候...',
|
pleaseWait: '請稍候...',
|
||||||
viewDetails: '查看詳情',
|
viewDetails: '查看詳情',
|
||||||
@@ -131,6 +132,7 @@ export default {
|
|||||||
light: '淺色',
|
light: '淺色',
|
||||||
dark: '深色',
|
dark: '深色',
|
||||||
auto: '跟隨系統',
|
auto: '跟隨系統',
|
||||||
|
autoUI: '自動佈局',
|
||||||
transparent: '透明',
|
transparent: '透明',
|
||||||
purple: '幻紫',
|
purple: '幻紫',
|
||||||
custom: '附加樣式',
|
custom: '附加樣式',
|
||||||
|
|||||||
Reference in New Issue
Block a user