diff --git a/data/diary/build.gradle.kts b/data/diary/build.gradle.kts index d69f648f7..4b8962617 100644 --- a/data/diary/build.gradle.kts +++ b/data/diary/build.gradle.kts @@ -25,4 +25,6 @@ android { dependencies { implementation(projects.data.presigned) + implementation(libs.mlkit.text.recognition) + implementation(libs.kotlinx.coroutines.play.services) } diff --git a/data/diary/src/main/java/com/hilingual/data/diary/di/MlKitModule.kt b/data/diary/src/main/java/com/hilingual/data/diary/di/MlKitModule.kt new file mode 100644 index 000000000..f3119625e --- /dev/null +++ b/data/diary/src/main/java/com/hilingual/data/diary/di/MlKitModule.kt @@ -0,0 +1,19 @@ +package com.hilingual.data.diary.di + +import com.google.mlkit.vision.text.TextRecognition +import com.google.mlkit.vision.text.TextRecognizer +import com.google.mlkit.vision.text.latin.TextRecognizerOptions +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import jakarta.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object MlKitModule { + @Provides + @Singleton + fun provideTextRecognizer(): TextRecognizer = + TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS) +} \ No newline at end of file diff --git a/data/diary/src/main/java/com/hilingual/data/diary/di/RepositoryModule.kt b/data/diary/src/main/java/com/hilingual/data/diary/di/RepositoryModule.kt index 6f6645b19..dc8504b0d 100644 --- a/data/diary/src/main/java/com/hilingual/data/diary/di/RepositoryModule.kt +++ b/data/diary/src/main/java/com/hilingual/data/diary/di/RepositoryModule.kt @@ -18,7 +18,9 @@ package com.hilingual.data.diary.di import com.hilingual.data.diary.localstorage.DiaryTempRepository import com.hilingual.data.diary.localstorage.DiaryTempRepositoryImpl import com.hilingual.data.diary.repository.DiaryRepository +import com.hilingual.data.diary.repository.TextRecognitionRepository import com.hilingual.data.diary.repositoryimpl.DiaryRepositoryImpl +import com.hilingual.data.diary.repositoryimpl.TextRecognitionRepositoryImpl import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -35,4 +37,8 @@ internal abstract class RepositoryModule { @Binds @Singleton abstract fun bindDiaryTempRepository(impl: DiaryTempRepositoryImpl): DiaryTempRepository + + @Binds + @Singleton + abstract fun bindTextRecognitionRepository(impl: TextRecognitionRepositoryImpl): TextRecognitionRepository } diff --git a/data/diary/src/main/java/com/hilingual/data/diary/repository/TextRecognitionRepository.kt b/data/diary/src/main/java/com/hilingual/data/diary/repository/TextRecognitionRepository.kt new file mode 100644 index 000000000..1584eb741 --- /dev/null +++ b/data/diary/src/main/java/com/hilingual/data/diary/repository/TextRecognitionRepository.kt @@ -0,0 +1,7 @@ +package com.hilingual.data.diary.repository + +import android.net.Uri + +interface TextRecognitionRepository { + suspend fun extractTextFromImage(uri: Uri): Result +} diff --git a/data/diary/src/main/java/com/hilingual/data/diary/repositoryimpl/TextRecognitionRepositoryImpl.kt b/data/diary/src/main/java/com/hilingual/data/diary/repositoryimpl/TextRecognitionRepositoryImpl.kt new file mode 100644 index 000000000..29bc42b5d --- /dev/null +++ b/data/diary/src/main/java/com/hilingual/data/diary/repositoryimpl/TextRecognitionRepositoryImpl.kt @@ -0,0 +1,26 @@ +package com.hilingual.data.diary.repositoryimpl + +import android.content.Context +import android.net.Uri +import com.google.mlkit.vision.common.InputImage +import com.google.mlkit.vision.text.TextRecognizer +import com.hilingual.data.diary.repository.TextRecognitionRepository +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.tasks.await +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class TextRecognitionRepositoryImpl @Inject constructor( + @ApplicationContext private val context: Context, + private val recognizer: TextRecognizer +) : TextRecognitionRepository { + + override suspend fun extractTextFromImage(uri: Uri): Result = + withContext(Dispatchers.IO) { + runCatching { + val image = InputImage.fromFilePath(context, uri) + recognizer.process(image).await().text + } + } +} diff --git a/presentation/diarywrite/build.gradle.kts b/presentation/diarywrite/build.gradle.kts index f413a64f9..fdb00b0b2 100644 --- a/presentation/diarywrite/build.gradle.kts +++ b/presentation/diarywrite/build.gradle.kts @@ -28,9 +28,5 @@ dependencies { implementation(projects.data.calendar) implementation(projects.data.diary) - // ML Kit - implementation(libs.mlkit.text.recognition) - implementation(libs.kotlinx.coroutines.play.services) - implementation(libs.lottie) } diff --git a/presentation/diarywrite/src/main/java/com/hilingual/presentation/diarywrite/DiaryWriteViewModel.kt b/presentation/diarywrite/src/main/java/com/hilingual/presentation/diarywrite/DiaryWriteViewModel.kt index 274dfb05f..07606e3ea 100644 --- a/presentation/diarywrite/src/main/java/com/hilingual/presentation/diarywrite/DiaryWriteViewModel.kt +++ b/presentation/diarywrite/src/main/java/com/hilingual/presentation/diarywrite/DiaryWriteViewModel.kt @@ -15,24 +15,20 @@ */ package com.hilingual.presentation.diarywrite -import android.content.Context import android.net.Uri import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.navigation.toRoute -import com.google.mlkit.vision.common.InputImage -import com.google.mlkit.vision.text.TextRecognition -import com.google.mlkit.vision.text.latin.TextRecognizerOptions import com.hilingual.core.common.extension.onLogFailure import com.hilingual.core.common.util.UiState import com.hilingual.core.navigation.DiaryWriteMode import com.hilingual.data.calendar.repository.CalendarRepository import com.hilingual.data.diary.localstorage.DiaryTempRepository import com.hilingual.data.diary.repository.DiaryRepository +import com.hilingual.data.diary.repository.TextRecognitionRepository import com.hilingual.presentation.diarywrite.navigation.DiaryWrite import dagger.hilt.android.lifecycle.HiltViewModel -import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -42,7 +38,6 @@ import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import kotlinx.coroutines.tasks.await import kotlinx.coroutines.withContext import timber.log.Timber import java.io.File @@ -52,10 +47,10 @@ import javax.inject.Inject @HiltViewModel internal class DiaryWriteViewModel @Inject constructor( savedStateHandle: SavedStateHandle, - @ApplicationContext private val context: Context, private val calendarRepository: CalendarRepository, private val diaryRepository: DiaryRepository, - private val diaryTempRepository: DiaryTempRepository + private val diaryTempRepository: DiaryTempRepository, + private val textRecognitionRepository: TextRecognitionRepository ) : ViewModel() { private val route: DiaryWrite = savedStateHandle.toRoute() @@ -186,22 +181,15 @@ internal class DiaryWriteViewModel @Inject constructor( fun extractTextFromImage(uri: Uri, tempFileToDelete: File? = null) { viewModelScope.launch { try { - runCatching { - withContext(Dispatchers.IO) { - val image = InputImage.fromFilePath(context, uri) - val recognizer = - TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS) - recognizer.process(image).await().text - } - }.onSuccess { extractedText -> - _uiState.update { - it.copy( - diaryText = extractedText.take(MAX_DIARY_TEXT_LENGTH) - ) + textRecognitionRepository.extractTextFromImage(uri) + .onSuccess { extractedText -> + _uiState.update { + it.copy( + diaryText = extractedText.take(MAX_DIARY_TEXT_LENGTH) + ) + } } - }.onFailure { throwable -> - Timber.tag("DiaryWriteViewModel").e(throwable, "Text recognition failed") - } + .onLogFailure { } } finally { withContext(Dispatchers.IO) { if (tempFileToDelete?.exists() == true) {