- CardNotifListenerService: 결제 알림(금액+승인/결제/카드) 가로채 백엔드로 전송 (토큰은 Capacitor Preferences에서, 결제성 알림만 전송) - CardNotifPlugin: 알림 접근 권한 확인/설정 열기 - AndroidManifest 서비스 등록, MainActivity 플러그인 등록 - 가계부 화면: 네이티브 미허용 시 '알림 접근 권한' 안내 배너 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { computed, nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { accountApi } from '@/api/accountApi'
|
||||
import IconBtn from '@/components/ui/IconBtn.vue'
|
||||
import { imageToBlob, parseReceiptText } from '@/utils/receiptOcr'
|
||||
import { cardNotif } from '@/native/cardNotif'
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
// @capacitor/camera 는 네이티브에서만 동적 로드 (웹은 file input 사용 — 정적 import 시 모바일 웹 청크 로드 실패 유발)
|
||||
|
||||
@@ -17,6 +18,16 @@ const error = ref(null)
|
||||
const pendingCount = ref(0) // 확인 필요(카드 알림 자동인식) 건수
|
||||
const editingPending = ref(false) // 수정 중인 항목이 미확인 건인지
|
||||
|
||||
// 카드 결제 알림 자동인식 권한 (네이티브 전용)
|
||||
const notifNative = cardNotif.isNative()
|
||||
const notifEnabled = ref(true) // 미허용일 때만 배너 노출
|
||||
async function checkNotifPermission() {
|
||||
if (notifNative) notifEnabled.value = await cardNotif.isEnabled()
|
||||
}
|
||||
function openNotifSettings() {
|
||||
cardNotif.openSettings()
|
||||
}
|
||||
|
||||
async function loadPendingCount() {
|
||||
try {
|
||||
pendingCount.value = (await accountApi.pendingCount()).count || 0
|
||||
@@ -491,6 +502,7 @@ onMounted(async () => {
|
||||
loadWallets()
|
||||
loadCategories()
|
||||
loadPendingCount()
|
||||
checkNotifPermission()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -501,6 +513,12 @@ onMounted(async () => {
|
||||
<IconBtn icon="plus" title="내역 추가" variant="primary" @click="openCreate" />
|
||||
</header>
|
||||
|
||||
<!-- 카드 결제 알림 자동인식 권한 안내 (네이티브, 미허용 시) -->
|
||||
<div v-if="notifNative && !notifEnabled" class="notif-banner">
|
||||
<span>💳 카드 결제 알림을 자동으로 가계부에 등록하려면 <b>알림 접근 권한</b>이 필요합니다.</span>
|
||||
<button type="button" class="notif-btn" @click="openNotifSettings">설정 열기</button>
|
||||
</div>
|
||||
|
||||
<div class="month-nav">
|
||||
<IconBtn icon="chevronLeft" title="이전 달" size="sm" @click="prevMonth" />
|
||||
<span class="period">{{ periodLabel }}</span>
|
||||
@@ -932,6 +950,29 @@ button.primary {
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.notif-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.6rem 0.8rem;
|
||||
margin-bottom: 1rem;
|
||||
border: 1px solid hsla(160, 100%, 37%, 0.4);
|
||||
border-radius: 8px;
|
||||
background: hsla(160, 100%, 37%, 0.08);
|
||||
font-size: 0.83rem;
|
||||
}
|
||||
.notif-btn {
|
||||
margin-left: auto;
|
||||
padding: 0.35rem 0.8rem;
|
||||
font-size: 0.82rem;
|
||||
border: 1px solid hsla(160, 100%, 37%, 1);
|
||||
border-radius: 4px;
|
||||
background: hsla(160, 100%, 37%, 1);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pending-count {
|
||||
margin-left: 0.5rem;
|
||||
font-size: 0.72rem;
|
||||
|
||||
Reference in New Issue
Block a user