mirror of
https://github.com/setube/ogame-vue-ts.git
synced 2026-05-12 07:55:11 +08:00
feat: 支持Android返回键退出确认与多语言提示
新增Android端返回键退出确认弹窗,防止误触直接退出应用。各语言包补充退出确认标题与提示语,提升多语言体验。依赖新增@capacitor/app,样式与主题适配同步优化。
This commit is contained in:
@@ -7,24 +7,14 @@
|
|||||||
<item name="colorPrimary">#1a1a2e</item>
|
<item name="colorPrimary">#1a1a2e</item>
|
||||||
<item name="colorPrimaryDark">#0f0f1a</item>
|
<item name="colorPrimaryDark">#0f0f1a</item>
|
||||||
<item name="colorAccent">#6366f1</item>
|
<item name="colorAccent">#6366f1</item>
|
||||||
<!-- 透明状态栏 -->
|
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
|
||||||
<item name="android:windowTranslucentStatus">false</item>
|
|
||||||
<item name="android:windowTranslucentNavigation">false</item>
|
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||||
<item name="windowActionBar">false</item>
|
<item name="windowActionBar">false</item>
|
||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
<item name="android:background">@null</item>
|
<item name="android:background">@null</item>
|
||||||
<!-- 透明状态栏 -->
|
<item name="android:statusBarColor">#1a1a2e</item>
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:navigationBarColor">#1a1a2e</item>
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
|
||||||
<item name="android:windowTranslucentStatus">false</item>
|
|
||||||
<item name="android:windowTranslucentNavigation">false</item>
|
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@capacitor/android": "^8.0.0",
|
"@capacitor/android": "^8.0.0",
|
||||||
|
"@capacitor/app": "^8.0.0",
|
||||||
"@capacitor/cli": "^8.0.0",
|
"@capacitor/cli": "^8.0.0",
|
||||||
"@capacitor/core": "^8.0.0",
|
"@capacitor/core": "^8.0.0",
|
||||||
"@tailwindcss/vite": "^4.1.17",
|
"@tailwindcss/vite": "^4.1.17",
|
||||||
|
|||||||
20
pnpm-lock.yaml
generated
20
pnpm-lock.yaml
generated
@@ -14,6 +14,9 @@ importers:
|
|||||||
'@capacitor/android':
|
'@capacitor/android':
|
||||||
specifier: ^8.0.0
|
specifier: ^8.0.0
|
||||||
version: 8.0.0(@capacitor/core@8.0.0)
|
version: 8.0.0(@capacitor/core@8.0.0)
|
||||||
|
'@capacitor/app':
|
||||||
|
specifier: ^8.0.0
|
||||||
|
version: 8.0.0(@capacitor/core@8.0.0)
|
||||||
'@capacitor/cli':
|
'@capacitor/cli':
|
||||||
specifier: ^8.0.0
|
specifier: ^8.0.0
|
||||||
version: 8.0.0
|
version: 8.0.0
|
||||||
@@ -650,6 +653,11 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@capacitor/core': ^8.0.0
|
'@capacitor/core': ^8.0.0
|
||||||
|
|
||||||
|
'@capacitor/app@8.0.0':
|
||||||
|
resolution: {integrity: sha512-OwzIkUs4w433Bu9WWAEbEYngXEfJXZ9Wmdb8eoaqzYBgB0W9/3Ed/mh6sAYPNBAZlpyarmewgP7Nb+d3Vrh+xA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@capacitor/core': '>=8.0.0'
|
||||||
|
|
||||||
'@capacitor/cli@8.0.0':
|
'@capacitor/cli@8.0.0':
|
||||||
resolution: {integrity: sha512-v9hEBi69xGxuuZhg55N031bMEenKaPSv71Il8C22VOOH6surDyv/MPeImN0oVfFc7eiklaW3rDFYVz6cmXfJWQ==}
|
resolution: {integrity: sha512-v9hEBi69xGxuuZhg55N031bMEenKaPSv71Il8C22VOOH6surDyv/MPeImN0oVfFc7eiklaW3rDFYVz6cmXfJWQ==}
|
||||||
engines: {node: '>=22.0.0'}
|
engines: {node: '>=22.0.0'}
|
||||||
@@ -968,8 +976,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==}
|
resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
'@electron/node-gyp@git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2':
|
'@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2':
|
||||||
resolution: {commit: 06b29aafb7708acef8b3669835c8a7857ebc92d2, repo: https://github.com/electron/node-gyp.git, type: git}
|
resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2}
|
||||||
version: 10.2.0-electron.1
|
version: 10.2.0-electron.1
|
||||||
engines: {node: '>=12.13.0'}
|
engines: {node: '>=12.13.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -5077,6 +5085,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@capacitor/core': 8.0.0
|
'@capacitor/core': 8.0.0
|
||||||
|
|
||||||
|
'@capacitor/app@8.0.0(@capacitor/core@8.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@capacitor/core': 8.0.0
|
||||||
|
|
||||||
'@capacitor/cli@8.0.0':
|
'@capacitor/cli@8.0.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ionic/cli-framework-output': 2.2.8
|
'@ionic/cli-framework-output': 2.2.8
|
||||||
@@ -5438,7 +5450,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@electron/node-gyp@git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2':
|
'@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2':
|
||||||
dependencies:
|
dependencies:
|
||||||
env-paths: 2.2.1
|
env-paths: 2.2.1
|
||||||
exponential-backoff: 3.1.3
|
exponential-backoff: 3.1.3
|
||||||
@@ -5475,7 +5487,7 @@ snapshots:
|
|||||||
|
|
||||||
'@electron/rebuild@3.7.0':
|
'@electron/rebuild@3.7.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@electron/node-gyp': git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2
|
'@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2
|
||||||
'@malept/cross-spawn-promise': 2.0.0
|
'@malept/cross-spawn-promise': 2.0.0
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
|
|||||||
38
src/App.vue
38
src/App.vue
@@ -428,6 +428,20 @@
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</SidebarProvider>
|
</SidebarProvider>
|
||||||
|
|
||||||
|
<!-- Android 退出确认对话框 -->
|
||||||
|
<AlertDialog v-model:open="exitDialogOpen">
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>{{ t('common.exitConfirmTitle') }}</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>{{ t('common.exitConfirmMessage') }}</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>{{ t('common.cancel') }}</AlertDialogCancel>
|
||||||
|
<AlertDialogAction @click="exitApp">{{ t('common.confirm') }}</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -528,6 +542,8 @@
|
|||||||
import { checkLatestVersion } from '@/utils/versionCheck'
|
import { checkLatestVersion } from '@/utils/versionCheck'
|
||||||
import { StarsBackground } from '@/components/ui/bg-stars'
|
import { StarsBackground } from '@/components/ui/bg-stars'
|
||||||
import { ParticlesBg } from '@/components/ui/particles-bg'
|
import { ParticlesBg } from '@/components/ui/particles-bg'
|
||||||
|
import { App as CapacitorApp } from '@capacitor/app'
|
||||||
|
import { Capacitor } from '@capacitor/core'
|
||||||
|
|
||||||
// 执行数据迁移(在 store 初始化之前)
|
// 执行数据迁移(在 store 初始化之前)
|
||||||
migrateGameData()
|
migrateGameData()
|
||||||
@@ -570,6 +586,8 @@
|
|||||||
const renameDialogOpen = ref(false)
|
const renameDialogOpen = ref(false)
|
||||||
const renamingPlanetId = ref<string | null>(null)
|
const renamingPlanetId = ref<string | null>(null)
|
||||||
const newPlanetName = ref('')
|
const newPlanetName = ref('')
|
||||||
|
// Android 退出确认对话框状态
|
||||||
|
const exitDialogOpen = ref(false)
|
||||||
// 功能解锁要求配置
|
// 功能解锁要求配置
|
||||||
const featureRequirements: Record<string, { building: BuildingType; level: number }> = {
|
const featureRequirements: Record<string, { building: BuildingType; level: number }> = {
|
||||||
'/research': { building: BuildingType.ResearchLab, level: 1 },
|
'/research': { building: BuildingType.ResearchLab, level: 1 },
|
||||||
@@ -2072,6 +2090,17 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// Android 返回键退出确认
|
||||||
|
if (Capacitor.isNativePlatform()) {
|
||||||
|
CapacitorApp.addListener('backButton', ({ canGoBack }) => {
|
||||||
|
if (canGoBack) {
|
||||||
|
router.back()
|
||||||
|
} else {
|
||||||
|
exitDialogOpen.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 启动版本检查定时器(每5分钟被动检查一次)
|
// 启动版本检查定时器(每5分钟被动检查一次)
|
||||||
versionCheckInterval.value = setInterval(async () => {
|
versionCheckInterval.value = setInterval(async () => {
|
||||||
const versionInfo = await checkLatestVersion(gameStore.player.lastVersionCheckTime || 0, (time: number) => {
|
const versionInfo = await checkLatestVersion(gameStore.player.lastVersionCheckTime || 0, (time: number) => {
|
||||||
@@ -2107,7 +2136,16 @@
|
|||||||
// 移除队列取消事件监听
|
// 移除队列取消事件监听
|
||||||
window.removeEventListener('cancel-build', handleCancelBuildEvent as EventListener)
|
window.removeEventListener('cancel-build', handleCancelBuildEvent as EventListener)
|
||||||
window.removeEventListener('cancel-research', handleCancelResearchEvent as EventListener)
|
window.removeEventListener('cancel-research', handleCancelResearchEvent as EventListener)
|
||||||
|
// 移除 Android 返回键监听
|
||||||
|
if (Capacitor.isNativePlatform()) {
|
||||||
|
CapacitorApp.removeAllListeners()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Android 退出应用
|
||||||
|
const exitApp = () => {
|
||||||
|
CapacitorApp.exitApp()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ export default {
|
|||||||
current: 'Aktuell',
|
current: 'Aktuell',
|
||||||
level: 'Stufe',
|
level: 'Stufe',
|
||||||
gmModeActivated: 'GM-Modus aktiviert! Überprüfen Sie das Navigationsmenü.',
|
gmModeActivated: 'GM-Modus aktiviert! Überprüfen Sie das Navigationsmenü.',
|
||||||
view: 'Anzeigen'
|
view: 'Anzeigen',
|
||||||
|
exitConfirmTitle: 'Spiel beenden',
|
||||||
|
exitConfirmMessage: 'Möchten Sie das Spiel wirklich beenden? Ihr Fortschritt wird automatisch gespeichert.'
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
requirementsNotMet: 'Anforderungen nicht erfüllt',
|
requirementsNotMet: 'Anforderungen nicht erfüllt',
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ export default {
|
|||||||
current: 'Current',
|
current: 'Current',
|
||||||
level: 'Level',
|
level: 'Level',
|
||||||
gmModeActivated: 'GM Mode Activated! Check the navigation menu.',
|
gmModeActivated: 'GM Mode Activated! Check the navigation menu.',
|
||||||
view: 'View'
|
view: 'View',
|
||||||
|
exitConfirmTitle: 'Exit Game',
|
||||||
|
exitConfirmMessage: 'Are you sure you want to exit? Your progress is saved automatically.'
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
requirementsNotMet: 'Requirements not met',
|
requirementsNotMet: 'Requirements not met',
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ export default {
|
|||||||
current: '現在',
|
current: '現在',
|
||||||
level: 'レベル',
|
level: 'レベル',
|
||||||
gmModeActivated: 'GMモードが有効になりました!ナビゲーションメニューをご確認ください。',
|
gmModeActivated: 'GMモードが有効になりました!ナビゲーションメニューをご確認ください。',
|
||||||
view: '表示'
|
view: '表示',
|
||||||
|
exitConfirmTitle: 'ゲーム終了',
|
||||||
|
exitConfirmMessage: 'ゲームを終了しますか?進行状況は自動的に保存されます。'
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
requirementsNotMet: '前提条件を満たしていません',
|
requirementsNotMet: '前提条件を満たしていません',
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ export default {
|
|||||||
current: '현재',
|
current: '현재',
|
||||||
level: '레벨',
|
level: '레벨',
|
||||||
gmModeActivated: 'GM 모드가 활성화되었습니다! 탐색 메뉴를 확인하세요.',
|
gmModeActivated: 'GM 모드가 활성화되었습니다! 탐색 메뉴를 확인하세요.',
|
||||||
view: '보기'
|
view: '보기',
|
||||||
|
exitConfirmTitle: '게임 종료',
|
||||||
|
exitConfirmMessage: '게임을 종료하시겠습니까? 진행 상황은 자동으로 저장됩니다.'
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
requirementsNotMet: '전제 조건 미충족',
|
requirementsNotMet: '전제 조건 미충족',
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ export default {
|
|||||||
current: 'Текущий',
|
current: 'Текущий',
|
||||||
level: 'Уровень',
|
level: 'Уровень',
|
||||||
gmModeActivated: 'Режим GM активирован! Проверьте навигационное меню.',
|
gmModeActivated: 'Режим GM активирован! Проверьте навигационное меню.',
|
||||||
view: 'Просмотр'
|
view: 'Просмотр',
|
||||||
|
exitConfirmTitle: 'Выйти из игры',
|
||||||
|
exitConfirmMessage: 'Вы уверены, что хотите выйти? Прогресс сохраняется автоматически.'
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
requirementsNotMet: 'Требования не выполнены',
|
requirementsNotMet: 'Требования не выполнены',
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ export default {
|
|||||||
current: '当前',
|
current: '当前',
|
||||||
level: '等级',
|
level: '等级',
|
||||||
gmModeActivated: 'GM 模式已激活!请查看导航菜单。',
|
gmModeActivated: 'GM 模式已激活!请查看导航菜单。',
|
||||||
view: '查看'
|
view: '查看',
|
||||||
|
exitConfirmTitle: '退出游戏',
|
||||||
|
exitConfirmMessage: '确定要退出游戏吗?游戏进度会自动保存。'
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
requirementsNotMet: '不满足前置条件',
|
requirementsNotMet: '不满足前置条件',
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ export default {
|
|||||||
current: '當前',
|
current: '當前',
|
||||||
level: '等級',
|
level: '等級',
|
||||||
gmModeActivated: 'GM 模式已啟用!請查看導航選單。',
|
gmModeActivated: 'GM 模式已啟用!請查看導航選單。',
|
||||||
view: '查看'
|
view: '查看',
|
||||||
|
exitConfirmTitle: '退出遊戲',
|
||||||
|
exitConfirmMessage: '確定要退出遊戲嗎?遊戲進度會自動儲存。'
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
requirementsNotMet: '不滿足前置條件',
|
requirementsNotMet: '不滿足前置條件',
|
||||||
|
|||||||
@@ -126,11 +126,6 @@
|
|||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
/* Android/Capacitor 安全区域适配 - 额外增加 8px 避免太靠近状态栏 */
|
|
||||||
padding-top: calc(env(safe-area-inset-top, 0px) + 8px);
|
|
||||||
padding-bottom: env(safe-area-inset-bottom, 0);
|
|
||||||
padding-left: env(safe-area-inset-left, 0);
|
|
||||||
padding-right: env(safe-area-inset-right, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 平滑过渡 */
|
/* 平滑过渡 */
|
||||||
|
|||||||
Reference in New Issue
Block a user