Skip to content

다시 대화하기(화면 이동), 삭제하기(카드 삭제하기) #143

Description

@theBettor

1. 대화 전체 보기 : eed379e

이 화면은 2개의 유즈케이스가 필요할듯(질문과, 답변)

2. 다시 대화하기

:
탐구 방법

  1. 추억카드 생성 -> 추억저장소 로 이동하게됨
  2. 피그마가 매우 불친절하게 되어있음.. '모니는 새로운 대화 내용이 아닌 이전 대화 데이터를 반영하여 그와 연결되는 대화를 시작한다.'
    -> MemoryCard의 text를 초기화해야겠다. 질문은 어떻게 해야할지 확신이 안선다.
  3. 그렇다면 뷰모델에 새로운 함수가 필요하다
    : 파라미터에 메모리카드가 필요할 것이고, 그 중에 text만 초기화해야함.

❗️❗️❗️-> 중단!!!

: text를 초기화한다는게 RoomDB를 업데이트 해야하기 때문에 엔티티로 변환하는 작업이 필요하대서 잘 몰라가지고 중단

3. 삭제하기 : 10f6267

: id는 뷰모델을 통해 삭제됨을 보여주고, 동시에 Routed의 파리미터는 전화면으로 가게 만들어줬다.

배경

사용자가 카드 상세 보기에서 삭제하기를 눌렀을 때 DB 및 UI에서 제거되어야 함
ViewModel은 UseCase만 의존해야 하므로, 직접 Repository를 호출하는 대신 전용 UseCase가 필요
Room에서 DELETE는 반드시 비동기(Dispatchers.IO) 에서 실행되어야 하므로 안전한 실행 흐름이 요구됨

🧩 Step 1. MemoryCardRepository에 삭제 함수 추가
🧩 Step 2. Repository 구현에 삭제 로직 추가 (LocalMemoryCardRepositoryImpl)

override suspend fun deleteMemoryCard(memoryCardId: String) {
    withContext(Dispatchers.IO) { // ✅ Room DB는 IO 디스패처에서 실행
        val id = memoryCardId.toLong()
        memoryCardDao.deleteMemoryStorageById(id)
    }
}

🧩 Step 3. Usecase생성
🧩 Step 4. MemoryStorageDetailViewModel에서 삭제 로직 추가
🧩 Step 5. MemoryStorageDetailScreen → BottomSheet로 삭제 이벤트 전달

BottomSheetForMemory(
    showBottomSheet = showBottomSheet,
    onDismiss = { showBottomSheet = false },
    onRestartConversation = {
        showBottomSheet = false
        onRestartConversation()
    },
    memoryCardId = memory?.id ?: "", // ✅ id 전달
    deleteCardRequest = deleteCardRequest // (String) -> Unit
)

🧩 Step 6. BottomSheetForMemory에서 삭제 요청 처리

Text(
    text = "삭제하기",
    modifier = Modifier
        .fillMaxWidth()
        .padding(top = 23.dp)
        .clickable {
            deleteCardRequest(memoryCardId) // 전달받은 ID 사용
        }
)

🧩 Step 7. MemoryStorageDetailRoute에서 ViewModel + 삭제 후처리 조합

when (uiState) {
        is MemoryStorageDetailUiState.Loading -> {
            // TODO: 로딩 UI
        }

        is MemoryStorageDetailUiState.Error -> {
            // TODO: 에러 UI
        }

        is MemoryStorageDetailUiState.Success -> {
            val state = uiState as MemoryStorageDetailUiState.Success
            when (state.screenState) {
                MemoryStorageDetailScreenState.Detail -> {
                    MemoryStorageDetailScreen(
                        memoryStorageDetailUiState = state,
                        onBackRequest = onBackRequest,
                        onShowConversation = viewModel::showConversation,
                        onRestartConversation = onRestartConversation,
                        deleteCardRequest = {
                            viewModel.deleteMemoryCard()
                        }
                    )
                }

                MemoryStorageDetailScreenState.Conversation -> {
                    ConversationView(
                        onDismiss = viewModel::showDetail,
                        onRestartConversation = onRestartConversation
                    )
                }
            }
        }
    }
    LaunchedEffect(Unit) {
        lifecycleOwner.lifecycleScope.launch {
            viewModel.event.collect { event ->
                when (event) {
                    is MemoryStorageDetailEvent.Deleted -> {
                        deleteCardRequest()
                    }

                    is MemoryStorageDetailEvent.DeleteError -> {
                        Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show()
                    }

                    else -> {}
                }
            }
        }
    }

✅ 테스트 결과 및 결론

  • ViewModel은 memoryCardId를 안전하게 처리하고 예외도 전송함
  • 실제 DB에서는 withContext(Dispatchers.IO) 덕분에 Room의 IllegalStateException 방지
  • 삭제 성공 시 Deleted 이벤트, 실패 시 DeleteError 이벤트로 사용자에게 피드백 제공
  • UI에서 Toast, popBackStack() 등으로 자연스러운 UX 흐름 제공 가능

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions