mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-10 17:42:50 +08:00
优化 PWA 安装提示组件
This commit is contained in:
@@ -3,12 +3,7 @@ import { usePWAInstall } from '@/composables/usePWAInstall'
|
||||
import { useToast } from 'vue-toastification'
|
||||
|
||||
const { t } = useI18n()
|
||||
const {
|
||||
isInstallable,
|
||||
isInstalled,
|
||||
showInstallPrompt,
|
||||
getInstallInstructions
|
||||
} = usePWAInstall()
|
||||
const { isInstallable, isInstalled, showInstallPrompt, getInstallInstructions } = usePWAInstall()
|
||||
|
||||
const showBanner = ref(false)
|
||||
const showInstructions = ref(false)
|
||||
@@ -28,14 +23,14 @@ onMounted(() => {
|
||||
const dismissedDate = new Date(dismissedTime)
|
||||
const now = new Date()
|
||||
const daysDiff = (now.getTime() - dismissedDate.getTime()) / (1000 * 60 * 60 * 24)
|
||||
|
||||
|
||||
// 如果距离上次关闭不到7天,不显示
|
||||
if (daysDiff < 7) {
|
||||
dismissed.value = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
showBanner.value = true
|
||||
}, 30000) // 30秒后显示
|
||||
})
|
||||
@@ -62,7 +57,21 @@ const dismissBanner = () => {
|
||||
}
|
||||
|
||||
// 获取平台特定的安装说明
|
||||
const instructions = computed(() => getInstallInstructions())
|
||||
const instructions = computed(() => {
|
||||
const rawInstructions = getInstallInstructions()
|
||||
const platformKey = rawInstructions.platformKey
|
||||
|
||||
// 获取平台显示名称
|
||||
const platformName = t(`pwa.platforms.${platformKey}`)
|
||||
|
||||
// 获取安装步骤
|
||||
const steps = t(`pwa.installSteps.${platformKey}`)
|
||||
|
||||
return {
|
||||
platform: platformName,
|
||||
steps: Array.isArray(steps) ? steps : [],
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -75,30 +84,17 @@ const instructions = computed(() => getInstallInstructions())
|
||||
leave-from-class="translate-y-0 opacity-100"
|
||||
leave-to-class="translate-y-full opacity-0"
|
||||
>
|
||||
<div
|
||||
v-if="shouldShowBanner && showBanner"
|
||||
class="pwa-install-banner"
|
||||
>
|
||||
<div v-if="shouldShowBanner && showBanner" class="pwa-install-banner">
|
||||
<div class="banner-content">
|
||||
<VIcon icon="mdi-cellphone-link" size="24" class="me-3" />
|
||||
<div class="flex-grow-1">
|
||||
<div class="font-weight-medium">安装 MoviePilot 应用</div>
|
||||
<div class="text-sm opacity-70">获得更好的离线体验和性能</div>
|
||||
<div class="font-weight-medium">{{ t('pwa.installApp') }}</div>
|
||||
<div class="text-sm opacity-70">{{ t('pwa.installDescription') }}</div>
|
||||
</div>
|
||||
<VBtn
|
||||
color="primary"
|
||||
size="small"
|
||||
variant="flat"
|
||||
@click="handleInstall"
|
||||
>
|
||||
安装
|
||||
<VBtn color="primary" size="small" variant="flat" @click="handleInstall">
|
||||
{{ t('pwa.install') }}
|
||||
</VBtn>
|
||||
<VBtn
|
||||
icon
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="dismissBanner"
|
||||
>
|
||||
<VBtn icon size="small" variant="text" @click="dismissBanner">
|
||||
<VIcon icon="mdi-close" />
|
||||
</VBtn>
|
||||
</div>
|
||||
@@ -106,20 +102,17 @@ const instructions = computed(() => getInstallInstructions())
|
||||
</Transition>
|
||||
|
||||
<!-- 手动安装说明对话框 -->
|
||||
<VDialog
|
||||
v-model="showInstructions"
|
||||
max-width="500"
|
||||
>
|
||||
<VDialog v-model="showInstructions" max-width="500">
|
||||
<VCard>
|
||||
<VCardTitle class="d-flex align-center">
|
||||
<VIcon icon="mdi-information-outline" class="me-2" />
|
||||
安装指南
|
||||
{{ t('pwa.installGuide') }}
|
||||
</VCardTitle>
|
||||
|
||||
|
||||
<VCardText>
|
||||
<div class="mb-4">
|
||||
<div class="text-subtitle-1 mb-2">
|
||||
在 {{ instructions.platform }} 上安装 MoviePilot:
|
||||
{{ t('pwa.installInstructions', { platform: instructions.platform }) }}
|
||||
</div>
|
||||
<VList density="compact">
|
||||
<VListItem
|
||||
@@ -131,24 +124,16 @@ const instructions = computed(() => getInstallInstructions())
|
||||
</VListItem>
|
||||
</VList>
|
||||
</div>
|
||||
|
||||
<VAlert
|
||||
type="info"
|
||||
variant="tonal"
|
||||
density="compact"
|
||||
>
|
||||
安装后,您可以从主屏幕快速访问 MoviePilot,并享受离线功能。
|
||||
|
||||
<VAlert type="info" variant="tonal" density="compact">
|
||||
{{ t('pwa.installNote') }}
|
||||
</VAlert>
|
||||
</VCardText>
|
||||
|
||||
|
||||
<VCardActions>
|
||||
<VSpacer />
|
||||
<VBtn
|
||||
color="primary"
|
||||
variant="text"
|
||||
@click="showInstructions = false"
|
||||
>
|
||||
知道了
|
||||
<VBtn color="primary" variant="text" @click="showInstructions = false">
|
||||
{{ t('pwa.gotIt') }}
|
||||
</VBtn>
|
||||
</VCardActions>
|
||||
</VCard>
|
||||
@@ -158,14 +143,13 @@ const instructions = computed(() => getInstallInstructions())
|
||||
<style scoped>
|
||||
.pwa-install-banner {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
background: rgb(var(--v-theme-surface));
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 12px;
|
||||
background: rgb(var(--v-theme-surface));
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 10%);
|
||||
inset-block-end: 20px;
|
||||
inset-inline: 20px;
|
||||
}
|
||||
|
||||
.banner-content {
|
||||
@@ -175,11 +159,10 @@ const instructions = computed(() => getInstallInstructions())
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
@media (width >= 600px) {
|
||||
.pwa-install-banner {
|
||||
left: auto;
|
||||
right: 20px;
|
||||
max-width: 400px;
|
||||
inset-inline: auto 20px;
|
||||
max-inline-size: 400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -25,10 +25,10 @@ export function usePWAInstall() {
|
||||
const isFullscreen = window.matchMedia('(display-mode: fullscreen)').matches
|
||||
const isMinimalUI = window.matchMedia('(display-mode: minimal-ui)').matches
|
||||
const isWindowControlsOverlay = window.matchMedia('(display-mode: window-controls-overlay)').matches
|
||||
|
||||
|
||||
// iOS Safari特殊检查
|
||||
const isIOSStandalone = (window.navigator as any).standalone === true
|
||||
|
||||
|
||||
return isStandalone || isFullscreen || isMinimalUI || isWindowControlsOverlay || isIOSStandalone
|
||||
}
|
||||
|
||||
@@ -42,18 +42,18 @@ export function usePWAInstall() {
|
||||
try {
|
||||
// 显示浏览器的安装提示
|
||||
await installPrompt.value.prompt()
|
||||
|
||||
|
||||
// 等待用户响应
|
||||
const { outcome } = await installPrompt.value.userChoice
|
||||
installOutcome.value = outcome
|
||||
|
||||
|
||||
// 如果用户接受安装,清除安装提示
|
||||
if (outcome === 'accepted') {
|
||||
isInstallable.value = false
|
||||
installPrompt.value = null
|
||||
isInstalled.value = true
|
||||
}
|
||||
|
||||
|
||||
return outcome === 'accepted'
|
||||
} catch (error) {
|
||||
console.error('Failed to show install prompt:', error)
|
||||
@@ -65,7 +65,7 @@ export function usePWAInstall() {
|
||||
const handleBeforeInstallPrompt = (e: BeforeInstallPromptEvent) => {
|
||||
// 阻止默认行为
|
||||
e.preventDefault()
|
||||
|
||||
|
||||
// 保存安装提示
|
||||
installPrompt.value = e
|
||||
isInstallable.value = true
|
||||
@@ -103,48 +103,48 @@ export function usePWAInstall() {
|
||||
|
||||
if (isIOS && isSafari) {
|
||||
return {
|
||||
platform: 'iOS Safari',
|
||||
steps: [
|
||||
'点击浏览器底部的分享按钮',
|
||||
'向下滑动并点击"添加到主屏幕"',
|
||||
'点击右上角的"添加"',
|
||||
],
|
||||
platform: 'ios',
|
||||
platformKey: 'ios',
|
||||
}
|
||||
} else if (isAndroid && isChrome) {
|
||||
return {
|
||||
platform: 'Android Chrome',
|
||||
steps: [
|
||||
'点击浏览器右上角的菜单按钮(三个点)',
|
||||
'选择"添加到主屏幕"',
|
||||
'点击"添加"确认',
|
||||
],
|
||||
platform: 'android',
|
||||
platformKey: 'android',
|
||||
}
|
||||
} else if (isEdge) {
|
||||
return {
|
||||
platform: 'Microsoft Edge',
|
||||
steps: [
|
||||
'点击地址栏右侧的安装按钮',
|
||||
'或点击菜单中的"应用" > "安装此站点"',
|
||||
'点击"安装"确认',
|
||||
],
|
||||
platform: 'edge',
|
||||
platformKey: 'edge',
|
||||
}
|
||||
} else if (isFirefox && isAndroid) {
|
||||
return {
|
||||
platform: 'Firefox Android',
|
||||
steps: [
|
||||
'点击浏览器右上角的菜单按钮',
|
||||
'选择"安装"',
|
||||
'点击"添加到主屏幕"',
|
||||
],
|
||||
platform: 'firefox',
|
||||
platformKey: 'android', // Firefox on Android uses similar steps to Chrome
|
||||
}
|
||||
} else if (isFirefox) {
|
||||
return {
|
||||
platform: 'firefox',
|
||||
platformKey: 'firefox',
|
||||
}
|
||||
} else if (isChrome) {
|
||||
return {
|
||||
platform: 'chrome',
|
||||
platformKey: 'chrome',
|
||||
}
|
||||
} else if (isSafari) {
|
||||
return {
|
||||
platform: 'safari',
|
||||
platformKey: 'safari',
|
||||
}
|
||||
} else if (isAndroid) {
|
||||
return {
|
||||
platform: 'mobile',
|
||||
platformKey: 'mobile',
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
platform: '您的浏览器',
|
||||
steps: [
|
||||
'查看浏览器的菜单或设置',
|
||||
'寻找"安装应用"或"添加到主屏幕"选项',
|
||||
'按照提示完成安装',
|
||||
],
|
||||
platform: 'desktop',
|
||||
platformKey: 'desktop',
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,16 +152,16 @@ export function usePWAInstall() {
|
||||
onMounted(() => {
|
||||
// 检查是否已安装
|
||||
isInstalled.value = checkIfInstalled()
|
||||
|
||||
|
||||
// 监听安装提示事件
|
||||
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt)
|
||||
|
||||
|
||||
// 监听安装成功事件
|
||||
window.addEventListener('appinstalled', handleAppInstalled)
|
||||
|
||||
|
||||
// 监听display-mode变化
|
||||
const mediaQuery = window.matchMedia('(display-mode: standalone)')
|
||||
mediaQuery.addEventListener('change', (e) => {
|
||||
mediaQuery.addEventListener('change', e => {
|
||||
isInstalled.value = e.matches
|
||||
})
|
||||
})
|
||||
@@ -179,4 +179,4 @@ export function usePWAInstall() {
|
||||
showInstallPrompt,
|
||||
getInstallInstructions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export function useRecentPlugins() {
|
||||
// 按访问时间倒序排列
|
||||
return recentPlugins.sort((a, b) => b.access_time - a.access_time).map(recentPluginToPlugin)
|
||||
} catch (error) {
|
||||
console.error('获取最近访问插件失败:', error)
|
||||
console.error(error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ export function useRecentPlugins() {
|
||||
|
||||
localStorage.setItem(RECENT_PLUGINS_KEY, JSON.stringify(recentPlugins))
|
||||
} catch (error) {
|
||||
console.error('保存最近访问插件失败:', error)
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ export function useRecentPlugins() {
|
||||
try {
|
||||
localStorage.removeItem(RECENT_PLUGINS_KEY)
|
||||
} catch (error) {
|
||||
console.error('清除最近访问插件失败:', error)
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ export function useRecentPlugins() {
|
||||
|
||||
localStorage.setItem(RECENT_PLUGINS_KEY, JSON.stringify(recentPlugins))
|
||||
} catch (error) {
|
||||
console.error('移除最近访问插件失败:', error)
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,76 @@ export default {
|
||||
online: 'Online Mode',
|
||||
onlineMessage: 'Network connection restored',
|
||||
},
|
||||
pwa: {
|
||||
installApp: 'Install MoviePilot App',
|
||||
installDescription: 'Get better offline experience and performance',
|
||||
install: 'Install',
|
||||
installSuccess: 'App installed successfully!',
|
||||
installGuide: 'Installation Guide',
|
||||
installInstructions: 'Install MoviePilot on {platform}:',
|
||||
installNote: 'After installation, you can quickly access MoviePilot from your home screen and enjoy offline features.',
|
||||
gotIt: 'Got it',
|
||||
// Platform specific descriptions
|
||||
platforms: {
|
||||
ios: 'iOS',
|
||||
android: 'Android',
|
||||
chrome: 'Chrome',
|
||||
edge: 'Edge',
|
||||
firefox: 'Firefox',
|
||||
safari: 'Safari',
|
||||
desktop: 'Desktop',
|
||||
mobile: 'Mobile',
|
||||
other: 'Other Browser',
|
||||
},
|
||||
// Installation steps
|
||||
installSteps: {
|
||||
ios: [
|
||||
'Tap the share button at the bottom of the browser',
|
||||
'Select "Add to Home Screen"',
|
||||
'Tap "Add" to confirm installation',
|
||||
],
|
||||
android: [
|
||||
'Tap the browser menu (three dots)',
|
||||
'Select "Add to Home Screen" or "Install App"',
|
||||
'Tap "Install" to confirm',
|
||||
],
|
||||
chrome: [
|
||||
'Click the install icon in the address bar',
|
||||
'Or click "Install MoviePilot" in the browser menu',
|
||||
'Click "Install" to confirm',
|
||||
],
|
||||
edge: [
|
||||
'Click the app icon in the address bar',
|
||||
'Select "Install this site as an app"',
|
||||
'Click "Install" to confirm',
|
||||
],
|
||||
firefox: [
|
||||
'Click the install icon in the address bar',
|
||||
'Select "Install"',
|
||||
'Confirm installation to desktop',
|
||||
],
|
||||
safari: [
|
||||
'Click the share button',
|
||||
'Select "Add to Home Screen"',
|
||||
'Tap "Add" to confirm',
|
||||
],
|
||||
desktop: [
|
||||
'Click the install icon in the address bar',
|
||||
'Select "Install App"',
|
||||
'Follow the prompts to complete installation',
|
||||
],
|
||||
mobile: [
|
||||
'Tap the browser menu',
|
||||
'Select "Add to Home Screen"',
|
||||
'Confirm installation',
|
||||
],
|
||||
other: [
|
||||
'Look for "Install" option in your browser',
|
||||
'Usually in the address bar or menu',
|
||||
'Follow the prompts to complete installation',
|
||||
],
|
||||
},
|
||||
},
|
||||
login: {
|
||||
wallpapers: 'Wallpapers',
|
||||
username: 'Username',
|
||||
|
||||
@@ -148,6 +148,76 @@ export default {
|
||||
online: '在线模式',
|
||||
onlineMessage: '网络连接已恢复',
|
||||
},
|
||||
pwa: {
|
||||
installApp: '安装 MoviePilot 应用',
|
||||
installDescription: '获得更好的离线体验和性能',
|
||||
install: '安装',
|
||||
installSuccess: '应用安装成功!',
|
||||
installGuide: '安装指南',
|
||||
installInstructions: '在 {platform} 上安装 MoviePilot:',
|
||||
installNote: '安装后,您可以从主屏幕快速访问 MoviePilot,并享受离线功能。',
|
||||
gotIt: '知道了',
|
||||
// 平台特定的说明
|
||||
platforms: {
|
||||
ios: 'iOS',
|
||||
android: 'Android',
|
||||
chrome: 'Chrome',
|
||||
edge: 'Edge',
|
||||
firefox: 'Firefox',
|
||||
safari: 'Safari',
|
||||
desktop: '桌面设备',
|
||||
mobile: '移动设备',
|
||||
other: '其他浏览器',
|
||||
},
|
||||
// 安装步骤
|
||||
installSteps: {
|
||||
ios: [
|
||||
'点击浏览器底部的分享按钮',
|
||||
'选择"添加到主屏幕"',
|
||||
'点击"添加"确认安装',
|
||||
],
|
||||
android: [
|
||||
'点击浏览器菜单(三个点)',
|
||||
'选择"添加到主屏幕"或"安装应用"',
|
||||
'点击"安装"确认',
|
||||
],
|
||||
chrome: [
|
||||
'点击地址栏右侧的安装图标',
|
||||
'或者点击浏览器菜单中的"安装 MoviePilot"',
|
||||
'点击"安装"确认',
|
||||
],
|
||||
edge: [
|
||||
'点击地址栏右侧的应用图标',
|
||||
'选择"安装此站点为应用"',
|
||||
'点击"安装"确认',
|
||||
],
|
||||
firefox: [
|
||||
'点击地址栏右侧的安装图标',
|
||||
'选择"安装"',
|
||||
'确认安装到桌面',
|
||||
],
|
||||
safari: [
|
||||
'点击分享按钮',
|
||||
'选择"添加到主屏幕"',
|
||||
'点击"添加"确认',
|
||||
],
|
||||
desktop: [
|
||||
'点击地址栏右侧的安装图标',
|
||||
'选择"安装应用"',
|
||||
'按照提示完成安装',
|
||||
],
|
||||
mobile: [
|
||||
'点击浏览器菜单',
|
||||
'选择"添加到主屏幕"',
|
||||
'确认安装',
|
||||
],
|
||||
other: [
|
||||
'查找浏览器中的"安装"选项',
|
||||
'通常在地址栏或菜单中',
|
||||
'按照提示完成安装',
|
||||
],
|
||||
},
|
||||
},
|
||||
login: {
|
||||
wallpapers: '壁纸',
|
||||
username: '用户名',
|
||||
|
||||
@@ -149,6 +149,76 @@ export default {
|
||||
online: '在線模式',
|
||||
onlineMessage: '網絡連接已恢復',
|
||||
},
|
||||
pwa: {
|
||||
installApp: '安裝 MoviePilot 應用',
|
||||
installDescription: '獲得更好的離線體驗和性能',
|
||||
install: '安裝',
|
||||
installSuccess: '應用安裝成功!',
|
||||
installGuide: '安裝指南',
|
||||
installInstructions: '在 {platform} 上安裝 MoviePilot:',
|
||||
installNote: '安裝後,您可以從主屏幕快速訪問 MoviePilot,並享受離線功能。',
|
||||
gotIt: '知道了',
|
||||
// 平台特定的說明
|
||||
platforms: {
|
||||
ios: 'iOS',
|
||||
android: 'Android',
|
||||
chrome: 'Chrome',
|
||||
edge: 'Edge',
|
||||
firefox: 'Firefox',
|
||||
safari: 'Safari',
|
||||
desktop: '桌面設備',
|
||||
mobile: '移動設備',
|
||||
other: '其他瀏覽器',
|
||||
},
|
||||
// 安裝步驟
|
||||
installSteps: {
|
||||
ios: [
|
||||
'點擊瀏覽器底部的分享按鈕',
|
||||
'選擇"添加到主屏幕"',
|
||||
'點擊"添加"確認安裝',
|
||||
],
|
||||
android: [
|
||||
'點擊瀏覽器菜單(三個點)',
|
||||
'選擇"添加到主屏幕"或"安裝應用"',
|
||||
'點擊"安裝"確認',
|
||||
],
|
||||
chrome: [
|
||||
'點擊地址欄右側的安裝圖標',
|
||||
'或者點擊瀏覽器菜單中的"安裝 MoviePilot"',
|
||||
'點擊"安裝"確認',
|
||||
],
|
||||
edge: [
|
||||
'點擊地址欄右側的應用圖標',
|
||||
'選擇"安裝此站點為應用"',
|
||||
'點擊"安裝"確認',
|
||||
],
|
||||
firefox: [
|
||||
'點擊地址欄右側的安裝圖標',
|
||||
'選擇"安裝"',
|
||||
'確認安裝到桌面',
|
||||
],
|
||||
safari: [
|
||||
'點擊分享按鈕',
|
||||
'選擇"添加到主屏幕"',
|
||||
'點擊"添加"確認',
|
||||
],
|
||||
desktop: [
|
||||
'點擊地址欄右側的安裝圖標',
|
||||
'選擇"安裝應用"',
|
||||
'按照提示完成安裝',
|
||||
],
|
||||
mobile: [
|
||||
'點擊瀏覽器菜單',
|
||||
'選擇"添加到主屏幕"',
|
||||
'確認安裝',
|
||||
],
|
||||
other: [
|
||||
'查找瀏覽器中的"安裝"選項',
|
||||
'通常在地址欄或菜單中',
|
||||
'按照提示完成安裝',
|
||||
],
|
||||
},
|
||||
},
|
||||
login: {
|
||||
wallpapers: '壁紙',
|
||||
username: '用戶名',
|
||||
|
||||
Reference in New Issue
Block a user