fix: 하단 내비 뒤로 버튼도 하드웨어 뒤로와 동일 동작
CI / build (push) Failing after 15m32s

- 통합 핸들러 appBack.handleBack 추출: 오버레이 닫기 → 화면 뒤로 →
  최상위에서 '한 번 더 누르면 종료' 토스트(네이티브)
- 하단 내비 뒤로 버튼이 옛 로직(홈에서 무반응)이라 하드웨어 뒤로와
  동작이 달랐던 문제 해결 — 둘이 같은 핸들러 사용
- capacitor.js 중복 로직 제거

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-06-29 09:25:57 +09:00
parent 6972cb5a63
commit b50a81028f
3 changed files with 45 additions and 30 deletions
+3 -27
View File
@@ -1,37 +1,13 @@
// Capacitor 네이티브(안드로이드) 통합. 웹에서는 no-op. // Capacitor 네이티브(안드로이드) 통합. 웹에서는 no-op.
import { Capacitor } from '@capacitor/core' import { Capacitor } from '@capacitor/core'
import { App as CapApp } from '@capacitor/app' import { App as CapApp } from '@capacitor/app'
import { useUiStore } from '@/stores/ui' import { handleBack } from '@/composables/appBack'
import { appLock } from '@/composables/appLock'
export function setupCapacitor(router) { export function setupCapacitor(router) {
if (!Capacitor.isNativePlatform()) return if (!Capacitor.isNativePlatform()) return
const ui = useUiStore() // 안드로이드 하드웨어 뒤로가기 → 하단 내비 뒤로 버튼과 동일한 통합 처리
let exitArmed = false CapApp.addListener('backButton', () => handleBack(router))
let exitTimer = null
// 안드로이드 하드웨어 뒤로가기 우선순위:
// 1) 잠금 화면이면 우회 불가 → 종료
// 2) 열린 전역 오버레이(회원가입/로그인/비번/사이드바) 닫기
// 3) 화면 뒤로
// 4) 최상위에서 한 번 더 누르면 종료(실수 종료 방지)
CapApp.addListener('backButton', ({ canGoBack }) => {
if (appLock.state.locked) { CapApp.exitApp(); return }
if (ui.signupOpen) { ui.closeSignup(); return }
if (ui.loginOpen) { ui.closeLogin(); return }
if (ui.passwordOpen) { ui.closePassword(); return }
if (ui.sidebarOpen) { ui.closeSidebar(); return }
if (canGoBack && window.history.length > 1) { router.back(); return }
if (exitArmed) { CapApp.exitApp(); return }
exitArmed = true
window.dispatchEvent(new CustomEvent('app:toast', { detail: '한 번 더 누르면 종료됩니다' }))
clearTimeout(exitTimer)
exitTimer = setTimeout(() => { exitArmed = false }, 2000)
})
// 네이티브 표시용 클래스 (safe-area 등 스타일 분기) // 네이티브 표시용 클래스 (safe-area 등 스타일 분기)
document.documentElement.classList.add('is-native') document.documentElement.classList.add('is-native')
+3 -3
View File
@@ -1,6 +1,7 @@
<script setup> <script setup>
import { computed } from 'vue' import { computed } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { handleBack } from '@/composables/appBack'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
@@ -9,9 +10,8 @@ const isHome = computed(() => route.path === '/')
const isSettings = computed(() => route.path.startsWith('/settings')) const isSettings = computed(() => route.path.startsWith('/settings'))
function goBack() { function goBack() {
// 히스토리가 있으면 뒤로, 없으면 홈으로 (앱 첫 화면에서 빠져나가지 않게) // 하드웨어 뒤로가기와 동일 동작(오버레이 닫기 → 화면 뒤로 → 최상위 종료 안내)
if (window.history.length > 1) router.back() handleBack(router)
else router.push('/')
} }
function goForward() { function goForward() {
router.forward() router.forward()
+39
View File
@@ -0,0 +1,39 @@
import { Capacitor } from '@capacitor/core'
import { App as CapApp } from '@capacitor/app'
import { useUiStore } from '@/stores/ui'
import { appLock } from '@/composables/appLock'
// 통합 뒤로가기 처리 — 하드웨어 뒤로(capacitor.js)와 하단 내비 뒤로 버튼이 동일 동작.
// 우선순위:
// 1) 잠금 화면이면 우회 불가 → (네이티브) 종료
// 2) 열린 전역 오버레이(회원가입/로그인/비번/사이드바) 닫기
// 3) 화면 뒤로(히스토리)
// 4) 최상위에서 '한 번 더 누르면 종료'(네이티브만, 실수 종료 방지)
let exitArmed = false
let exitTimer = null
export function handleBack(router) {
const native = Capacitor.isNativePlatform()
const ui = useUiStore()
if (appLock.state.locked) {
if (native) CapApp.exitApp()
return
}
if (ui.signupOpen) { ui.closeSignup(); return }
if (ui.loginOpen) { ui.closeLogin(); return }
if (ui.passwordOpen) { ui.closePassword(); return }
if (ui.sidebarOpen) { ui.closeSidebar(); return }
if (window.history.length > 1) { router.back(); return }
// 최상위(더 갈 곳 없음)
if (native) {
if (exitArmed) { CapApp.exitApp(); return }
exitArmed = true
window.dispatchEvent(new CustomEvent('app:toast', { detail: '한 번 더 누르면 종료됩니다' }))
clearTimeout(exitTimer)
exitTimer = setTimeout(() => { exitArmed = false }, 2000)
}
}