@@ -2,6 +2,7 @@ package com.ninecraft.booket.feature.record.ocr
22
33import android.net.Uri
44import androidx.compose.runtime.Composable
5+ import androidx.compose.runtime.LaunchedEffect
56import androidx.compose.runtime.getValue
67import androidx.compose.runtime.mutableStateOf
78import androidx.compose.runtime.rememberCoroutineScope
@@ -27,6 +28,7 @@ import kotlinx.collections.immutable.persistentListOf
2728import kotlinx.collections.immutable.persistentSetOf
2829import kotlinx.collections.immutable.toPersistentList
2930import kotlinx.collections.immutable.toPersistentSet
31+ import kotlinx.coroutines.delay
3032import kotlinx.coroutines.launch
3133
3234@AssistedInject
@@ -44,6 +46,7 @@ class OcrPresenter(
4446
4547 companion object {
4648 private const val RECORD_OCR_SENTENCE = " record_OCR_sentence"
49+ private const val CAMERA_MAX_FAILURES = 2
4750 }
4851
4952 @Composable
@@ -56,11 +59,53 @@ class OcrPresenter(
5659 var selectedIndices by rememberRetained { mutableStateOf(persistentSetOf<Int >()) }
5760 var mergedSentence by rememberRetained { mutableStateOf(" " ) }
5861 var isTextDetectionFailed by rememberRetained { mutableStateOf(false ) }
62+ var isCameraRecognitionFailedDialogVisible by rememberRetained { mutableStateOf(false ) }
63+ var isGalleryRecognitionFailedDialogVisible by rememberRetained { mutableStateOf(false ) }
5964 var isRecaptureDialogVisible by rememberRetained { mutableStateOf(false ) }
6065 var isLoading by rememberRetained { mutableStateOf(false ) }
6166 var sideEffect by rememberRetained { mutableStateOf<OcrSideEffect ?>(null ) }
6267
63- fun recognizeText (imageUri : Uri ) {
68+ var cameraFailureCount by rememberRetained { mutableStateOf(0 ) }
69+
70+ LaunchedEffect (isTextDetectionFailed) {
71+ if (isTextDetectionFailed) {
72+ delay(2000 )
73+ isTextDetectionFailed = false
74+ }
75+ }
76+
77+ fun handleRecognitionSuccess (text : String ) {
78+ isTextDetectionFailed = false
79+ cameraFailureCount = 0
80+
81+ val sentences = text
82+ .split(" \n " )
83+ .map { it.trim() }
84+ .filter { it.isNotEmpty() }
85+
86+ sentenceList = sentences.toPersistentList()
87+ currentUi = OcrUi .RESULT
88+ analyticsHelper.logScreenView(RECORD_OCR_SENTENCE )
89+ }
90+
91+ fun handleRecognitionFailure (source : RecognizeSource ) {
92+ when (source) {
93+ RecognizeSource .CAMERA -> {
94+ isTextDetectionFailed = true
95+ cameraFailureCount + = 1
96+
97+ if (cameraFailureCount >= CAMERA_MAX_FAILURES ) {
98+ isCameraRecognitionFailedDialogVisible = true
99+ }
100+ }
101+
102+ RecognizeSource .GALLERY -> {
103+ isGalleryRecognitionFailedDialogVisible = true
104+ }
105+ }
106+ }
107+
108+ fun recognizeText (imageUri : Uri , source : RecognizeSource ) {
64109 scope.launch {
65110 try {
66111 isLoading = true
@@ -69,21 +114,13 @@ class OcrPresenter(
69114 val text = it.responses.firstOrNull()?.fullTextAnnotation?.text.orEmpty()
70115
71116 if (text.isNotBlank()) {
72- isTextDetectionFailed = false
73- val sentences = text
74- .split(" \n " )
75- .map { it.trim() }
76- .filter { it.isNotEmpty() }
77-
78- sentenceList = sentences.toPersistentList()
79- currentUi = OcrUi .RESULT
80- analyticsHelper.logScreenView(RECORD_OCR_SENTENCE )
117+ handleRecognitionSuccess(text)
81118 } else {
82- isTextDetectionFailed = true
119+ handleRecognitionFailure(source)
83120 }
84121 }
85122 .onFailure { exception ->
86- isTextDetectionFailed = true
123+ handleRecognitionFailure(source)
87124
88125 val handleErrorMessage = { message: String ->
89126 Logger .e(" Cloud Vision API Error: ${exception.message} " )
@@ -128,16 +165,20 @@ class OcrPresenter(
128165
129166 is OcrUiEvent .OnImageCaptured -> {
130167 isTextDetectionFailed = false
168+ isCameraRecognitionFailedDialogVisible = false
169+ isGalleryRecognitionFailedDialogVisible = false
131170
132- recognizeText(event.imageUri)
171+ recognizeText(event.imageUri, RecognizeSource . CAMERA )
133172 }
134173
135174 is OcrUiEvent .OnImageSelected -> {
136175 currentUi = OcrUi .IMAGE
137176 selectedImage = event.imageUri
177+ isTextDetectionFailed = false
178+ isGalleryRecognitionFailedDialogVisible = false
138179
139180 val pareUri = selectedImage.toUri()
140- recognizeText(pareUri)
181+ recognizeText(pareUri, RecognizeSource . GALLERY )
141182 }
142183
143184 is OcrUiEvent .OnReCaptureButtonClick -> {
@@ -168,9 +209,17 @@ class OcrPresenter(
168209 isRecaptureDialogVisible = false
169210 }
170211
171- OcrUiEvent .OnImageViewClosed -> {
212+ OcrUiEvent .OnImageContentClosed -> {
172213 currentUi = OcrUi .CAMERA
173214 }
215+
216+ OcrUiEvent .OnCameraRecognitionFailedDialogDismissed -> {
217+ isCameraRecognitionFailedDialogVisible = false
218+ }
219+
220+ OcrUiEvent .OnImageRecognitionFailedDialogDismissed -> {
221+ isGalleryRecognitionFailedDialogVisible = false
222+ }
174223 }
175224 }
176225
@@ -185,6 +234,8 @@ class OcrPresenter(
185234 sentenceList = sentenceList,
186235 selectedIndices = selectedIndices,
187236 isTextDetectionFailed = isTextDetectionFailed,
237+ isCameraRecognitionFailedDialogVisible = isCameraRecognitionFailedDialogVisible,
238+ isGalleryRecognitionFailedDialogVisible = isGalleryRecognitionFailedDialogVisible,
188239 isRecaptureDialogVisible = isRecaptureDialogVisible,
189240 isLoading = isLoading,
190241 sideEffect = sideEffect,
0 commit comments