Export PDF to preferred dir if it was defined

This commit is contained in:
Pierre-Yves Nicolas
2025-11-27 18:47:18 +01:00
committed by pynicolas
parent 7c9267a866
commit 53c9bc3630
15 changed files with 91 additions and 27 deletions

View File

@@ -117,6 +117,7 @@ dependencies {
implementation(libs.androidx.camera.view) implementation(libs.androidx.camera.view)
implementation(libs.androidx.datastore) implementation(libs.androidx.datastore)
implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.documentfile)
implementation(libs.protobuf.javalite) implementation(libs.protobuf.javalite)
implementation(libs.litert) implementation(libs.litert)
implementation(libs.litert.support) implementation(libs.litert.support)

View File

@@ -17,6 +17,7 @@ package org.fairscan.app
import android.Manifest import android.Manifest
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.ClipData import android.content.ClipData
import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -297,13 +298,15 @@ class MainActivity : ComponentActivity() {
private fun openPdf(fileUri: Uri?) { private fun openPdf(fileUri: Uri?) {
if (fileUri == null) return if (fileUri == null) return
val uri = FileProvider.getUriForFile( val uriToOpen: Uri =
this, if (fileUri.scheme == ContentResolver.SCHEME_CONTENT) {
"${applicationContext.packageName}.fileprovider", fileUri
fileUri.toFile() } else {
) val authority = "${applicationContext.packageName}.fileprovider"
FileProvider.getUriForFile(this, authority, fileUri.toFile())
}
val openIntent = Intent(Intent.ACTION_VIEW).apply { val openIntent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, PDF_MIME_TYPE) setDataAndType(uriToOpen, PDF_MIME_TYPE)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
} }
try { try {

View File

@@ -221,7 +221,7 @@ private fun TextFieldAndPdfInfos(
} }
if (uiState.savedFileUri != null) { if (uiState.savedFileUri != null) {
SavedPdfBar(onOpen) SavedPdfBar(uiState, onOpen)
} }
if (uiState.errorMessage != null) { if (uiState.errorMessage != null) {
ErrorBar(uiState.errorMessage) ErrorBar(uiState.errorMessage)
@@ -335,7 +335,8 @@ fun ExportButton(
} }
@Composable @Composable
private fun SavedPdfBar(onOpen: () -> Unit) { private fun SavedPdfBar(uiState: PdfGenerationUiState, onOpen: () -> Unit) {
val dirName = uiState.exportDirName?:stringResource(R.string.download_dirname)
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Absolute.SpaceBetween, horizontalArrangement = Arrangement.Absolute.SpaceBetween,
@@ -345,7 +346,7 @@ private fun SavedPdfBar(onOpen: () -> Unit) {
.padding(vertical = 8.dp, horizontal = 16.dp), .padding(vertical = 8.dp, horizontal = 16.dp),
) { ) {
Text( Text(
text = stringResource(R.string.pdf_saved_to), text = stringResource(R.string.pdf_saved_to, dirName),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
) )
@@ -428,6 +429,7 @@ fun PreviewExportScreenAfterSaveHorizontal() {
uiState = PdfGenerationUiState( uiState = PdfGenerationUiState(
generatedPdf = GeneratedPdf(file, 442897L, 3), generatedPdf = GeneratedPdf(file, 442897L, 3),
savedFileUri = file.toUri(), savedFileUri = file.toUri(),
exportDirName = "MyVeryVeryLongDirectoryName"
), ),
) )
} }

View File

@@ -22,6 +22,7 @@ data class PdfGenerationUiState(
val generatedPdf: GeneratedPdf? = null, val generatedPdf: GeneratedPdf? = null,
val desiredFilename: String = "", val desiredFilename: String = "",
val savedFileUri: Uri? = null, val savedFileUri: Uri? = null,
val exportDirName: String? = null,
val hasSharedPdf: Boolean = false, val hasSharedPdf: Boolean = false,
val errorMessage: String? = null, val errorMessage: String? = null,
) { ) {

View File

@@ -16,7 +16,9 @@ package org.fairscan.app.ui.screens.export
import android.content.Context import android.content.Context
import android.media.MediaScannerConnection import android.media.MediaScannerConnection
import android.net.Uri
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -27,6 +29,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
@@ -36,6 +39,7 @@ import org.fairscan.app.data.GeneratedPdf
import org.fairscan.app.data.PdfFileManager import org.fairscan.app.data.PdfFileManager
import org.fairscan.app.ui.screens.home.HomeViewModel import org.fairscan.app.ui.screens.home.HomeViewModel
import java.io.File import java.io.File
import java.io.FileInputStream
private const val PDF_MIME_TYPE = "application/pdf" private const val PDF_MIME_TYPE = "application/pdf"
@@ -48,6 +52,7 @@ class ExportViewModel(container: AppContainer): ViewModel() {
private val pdfFileManager = container.pdfFileManager private val pdfFileManager = container.pdfFileManager
private val imageRepository = container.imageRepository private val imageRepository = container.imageRepository
private val settingsRepository = container.settingsRepository
private val logger = container.logger private val logger = container.logger
private val _events = MutableSharedFlow<ExportEvent>() private val _events = MutableSharedFlow<ExportEvent>()
@@ -121,12 +126,6 @@ class ExportViewModel(container: AppContainer): ViewModel() {
return _pdfUiState.value.generatedPdf return _pdfUiState.value.generatedPdf
} }
fun saveFile(pdfFile: File): File {
val copiedFile = pdfFileManager.copyToExternalDir(pdfFile)
_pdfUiState.update { it.copy(savedFileUri = copiedFile.toUri()) }
return copiedFile
}
fun onSavePdfClicked() { fun onSavePdfClicked() {
viewModelScope.launch { viewModelScope.launch {
_events.emit(ExportEvent.RequestSavePdf) _events.emit(ExportEvent.RequestSavePdf)
@@ -142,13 +141,30 @@ class ExportViewModel(container: AppContainer): ViewModel() {
private suspend fun performPdfSave(context: Context, homeViewModel: HomeViewModel) { private suspend fun performPdfSave(context: Context, homeViewModel: HomeViewModel) {
try { try {
val pdf = getFinalPdf() ?: return val pdf = getFinalPdf() ?: return
val targetFile = saveFile(pdf.file)
mediaScan(context, targetFile) val exportDir = settingsRepository.exportDirUri.first()
var fileInDownloads: File? = null
val savedUri: Uri =
if (exportDir == null) {
fileInDownloads = pdfFileManager.copyToExternalDir(pdf.file)
fileInDownloads.toUri()
} else {
copyViaSaf(context, pdf.file, exportDir.toUri())
}
_pdfUiState.update {
it.copy(
savedFileUri = savedUri,
exportDirName = resolveExportDirName(context, exportDir?.toUri()))
}
fileInDownloads?.let { mediaScan(context, it) }
// TODO remove that call: that should be handled through the ExportEvent // TODO remove that call: that should be handled through the ExportEvent
homeViewModel.addRecentDocument( homeViewModel.addRecentDocument(
targetFile.absolutePath, // FIXME This is not a file path
savedUri.toString(),
pdf.pageCount pdf.pageCount
) )
} catch (e: Exception) { } catch (e: Exception) {
@@ -167,10 +183,40 @@ class ExportViewModel(container: AppContainer): ViewModel() {
) { _, _ -> continuation.resume(Unit) {} } ) { _, _ -> continuation.resume(Unit) {} }
} }
private fun copyViaSaf(
context: Context,
source: File,
exportDirUri: Uri,
): Uri {
val resolver = context.contentResolver
val tree = DocumentFile.fromTreeUri(context, exportDirUri)
?: throw IllegalStateException("Invalid SAF directory")
// Name collisions are handled automatically by SAF provider
val target = tree.createFile(PDF_MIME_TYPE, source.name)
?: throw IllegalStateException("Unable to create SAF file")
resolver.openOutputStream(target.uri)?.use { output ->
FileInputStream(source).use { input ->
input.copyTo(output)
}
} ?: throw IllegalStateException("Failed to open SAF output stream")
return target.uri
}
fun cleanUpOldPdfs(thresholdInMillis: Int) { fun cleanUpOldPdfs(thresholdInMillis: Int) {
pdfFileManager.cleanUpOldFiles(thresholdInMillis) pdfFileManager.cleanUpOldFiles(thresholdInMillis)
} }
private fun resolveExportDirName(context: Context, exportDirUri: Uri?): String? {
return if (exportDirUri == null) {
null
} else {
DocumentFile.fromTreeUri(context, exportDirUri)?.name
}
}
} }
data class PdfGenerationActions( data class PdfGenerationActions(

View File

@@ -15,6 +15,7 @@
<string name="delete_page_warning">Chcete smazat tuto stránku?</string> <string name="delete_page_warning">Chcete smazat tuto stránku?</string>
<string name="developer">Vývojář</string> <string name="developer">Vývojář</string>
<string name="discard_scan">Zrušit skenování</string> <string name="discard_scan">Zrušit skenování</string>
<string name="download_dirname">stažených</string>
<string name="end_scan">Ukončit skenování</string> <string name="end_scan">Ukončit skenování</string>
<string name="error">Chyba: %1$s</string> <string name="error">Chyba: %1$s</string>
<string name="error_no_document">Nebyl rozpoznán žádná dokument</string> <string name="error_no_document">Nebyl rozpoznán žádná dokument</string>
@@ -33,7 +34,7 @@
<string name="new_document_warning">Toto skenování bude ztraceno. Chcete pokračovat?</string> <string name="new_document_warning">Toto skenování bude ztraceno. Chcete pokračovat?</string>
<string name="open">Otevřít</string> <string name="open">Otevřít</string>
<string name="open_pdf">Otevřít PDF</string> <string name="open_pdf">Otevřít PDF</string>
<string name="pdf_saved_to">PDF bylo uloženo do stažených</string> <string name="pdf_saved_to">PDF bylo uloženo do %1s</string>
<string name="resume">Obnovit</string> <string name="resume">Obnovit</string>
<string name="save">Uložit</string> <string name="save">Uložit</string>
<string name="scan_button">Nové skenování</string> <string name="scan_button">Nové skenování</string>

View File

@@ -15,6 +15,7 @@
<string name="delete_page_warning">Möchten Sie diese Seite löschen?</string> <string name="delete_page_warning">Möchten Sie diese Seite löschen?</string>
<string name="developer">Entwickler</string> <string name="developer">Entwickler</string>
<string name="discard_scan">Löschen</string> <string name="discard_scan">Löschen</string>
<string name="download_dirname">Downloads</string>
<string name="end_scan">Scan beenden</string> <string name="end_scan">Scan beenden</string>
<string name="error">Fehler: %1$s</string> <string name="error">Fehler: %1$s</string>
<string name="error_no_document">Kein Dokument erkannt</string> <string name="error_no_document">Kein Dokument erkannt</string>
@@ -33,7 +34,7 @@
<string name="new_document_warning">Das aktuelle Dokument geht verloren. Möchten Sie fortfahren?</string> <string name="new_document_warning">Das aktuelle Dokument geht verloren. Möchten Sie fortfahren?</string>
<string name="open">Öffnen</string> <string name="open">Öffnen</string>
<string name="open_pdf">PDF öffnen</string> <string name="open_pdf">PDF öffnen</string>
<string name="pdf_saved_to">PDF gespeichert in Downloads</string> <string name="pdf_saved_to">PDF gespeichert in %1s</string>
<string name="resume">Fortsetzen</string> <string name="resume">Fortsetzen</string>
<string name="save">Speichern</string> <string name="save">Speichern</string>
<string name="scan_button">Neuer Scan</string> <string name="scan_button">Neuer Scan</string>

View File

@@ -15,6 +15,7 @@
<string name="delete_page_warning">¿Quieres eliminar esta página?</string> <string name="delete_page_warning">¿Quieres eliminar esta página?</string>
<string name="developer">Desarrollador</string> <string name="developer">Desarrollador</string>
<string name="discard_scan">Descartar escaneo</string> <string name="discard_scan">Descartar escaneo</string>
<string name="download_dirname">Descargas</string>
<string name="end_scan">Finalizar escaneo</string> <string name="end_scan">Finalizar escaneo</string>
<string name="error">Error: %1$s</string> <string name="error">Error: %1$s</string>
<string name="error_no_document">No se detectó ningún documento</string> <string name="error_no_document">No se detectó ningún documento</string>
@@ -33,7 +34,7 @@
<string name="new_document_warning">El escaneo actual se perderá. ¿Deseas continuar?</string> <string name="new_document_warning">El escaneo actual se perderá. ¿Deseas continuar?</string>
<string name="open">Abrir</string> <string name="open">Abrir</string>
<string name="open_pdf">Abrir PDF</string> <string name="open_pdf">Abrir PDF</string>
<string name="pdf_saved_to">PDF guardado en Descargas</string> <string name="pdf_saved_to">PDF guardado en %1s</string>
<string name="resume">Reanudar</string> <string name="resume">Reanudar</string>
<string name="save">Guardar</string> <string name="save">Guardar</string>
<string name="scan_button">Nuevo escaneo</string> <string name="scan_button">Nuevo escaneo</string>

View File

@@ -15,6 +15,7 @@
<string name="delete_page_warning">Voulez-vous supprimer cette page ?</string> <string name="delete_page_warning">Voulez-vous supprimer cette page ?</string>
<string name="developer">Développeur</string> <string name="developer">Développeur</string>
<string name="discard_scan">Supprimer le scan</string> <string name="discard_scan">Supprimer le scan</string>
<string name="download_dirname">Téléchargements</string>
<string name="end_scan">Terminer le scan</string> <string name="end_scan">Terminer le scan</string>
<string name="error">Erreur : %1$s</string> <string name="error">Erreur : %1$s</string>
<string name="error_no_document">Aucun document détecté</string> <string name="error_no_document">Aucun document détecté</string>
@@ -33,7 +34,7 @@
<string name="new_document_warning">Le scan en cours sera perdu. Voulez-vous continuer ?</string> <string name="new_document_warning">Le scan en cours sera perdu. Voulez-vous continuer ?</string>
<string name="open">Ouvrir</string> <string name="open">Ouvrir</string>
<string name="open_pdf">Ouvrir le PDF</string> <string name="open_pdf">Ouvrir le PDF</string>
<string name="pdf_saved_to">PDF enregistré dans Téléchargements</string> <string name="pdf_saved_to">PDF enregistré dans %1s</string>
<string name="resume">Reprendre</string> <string name="resume">Reprendre</string>
<string name="save">Enregistrer</string> <string name="save">Enregistrer</string>
<string name="scan_button">Nouveau scan</string> <string name="scan_button">Nouveau scan</string>

View File

@@ -15,6 +15,7 @@
<string name="delete_page_warning">Vuoi eliminare questa pagina?</string> <string name="delete_page_warning">Vuoi eliminare questa pagina?</string>
<string name="developer">Sviluppatore</string> <string name="developer">Sviluppatore</string>
<string name="discard_scan">Scarta scansione</string> <string name="discard_scan">Scarta scansione</string>
<string name="download_dirname">Download</string>
<string name="end_scan">Termina scansione</string> <string name="end_scan">Termina scansione</string>
<string name="error">Errore: %1$s</string> <string name="error">Errore: %1$s</string>
<string name="error_no_document">Nessun documento rilevato</string> <string name="error_no_document">Nessun documento rilevato</string>
@@ -33,7 +34,7 @@
<string name="new_document_warning">La scansiona attuale verrà persa. Vuoi continuare?</string> <string name="new_document_warning">La scansiona attuale verrà persa. Vuoi continuare?</string>
<string name="open">Apri</string> <string name="open">Apri</string>
<string name="open_pdf">Apri PDF</string> <string name="open_pdf">Apri PDF</string>
<string name="pdf_saved_to">PDF salvato in Download</string> <string name="pdf_saved_to">PDF salvato in %1s</string>
<string name="resume">Riprendi</string> <string name="resume">Riprendi</string>
<string name="save">Salva</string> <string name="save">Salva</string>
<string name="scan_button">Nuova scansione</string> <string name="scan_button">Nuova scansione</string>

View File

@@ -15,6 +15,7 @@
<string name="delete_page_warning">Deseja excluir esta página?</string> <string name="delete_page_warning">Deseja excluir esta página?</string>
<string name="developer">Desenvolvedor</string> <string name="developer">Desenvolvedor</string>
<string name="discard_scan">Descartar digitalização</string> <string name="discard_scan">Descartar digitalização</string>
<string name="download_dirname">Downloads</string>
<string name="end_scan">Finalizar digitalização</string> <string name="end_scan">Finalizar digitalização</string>
<string name="error">Erro: %1$s</string> <string name="error">Erro: %1$s</string>
<string name="error_no_document">Nenhum documento detectado</string> <string name="error_no_document">Nenhum documento detectado</string>
@@ -33,7 +34,7 @@
<string name="new_document_warning">A digitalização atual será perdida. Deseja continuar?</string> <string name="new_document_warning">A digitalização atual será perdida. Deseja continuar?</string>
<string name="open">Abrir</string> <string name="open">Abrir</string>
<string name="open_pdf">Abrir PDF</string> <string name="open_pdf">Abrir PDF</string>
<string name="pdf_saved_to">PDF salvo em Downloads</string> <string name="pdf_saved_to">PDF salvo em %1s</string>
<string name="resume">Retomar</string> <string name="resume">Retomar</string>
<string name="save">Salvar</string> <string name="save">Salvar</string>
<string name="scan_button">Nova digitalização</string> <string name="scan_button">Nova digitalização</string>

View File

@@ -15,6 +15,7 @@
<string name="delete_page_warning">Вы желаете удалить эту страницу?</string> <string name="delete_page_warning">Вы желаете удалить эту страницу?</string>
<string name="developer">Разработчик</string> <string name="developer">Разработчик</string>
<string name="discard_scan">Отказаться</string> <string name="discard_scan">Отказаться</string>
<string name="download_dirname">Download</string>
<string name="end_scan">Закончить</string> <string name="end_scan">Закончить</string>
<string name="error">Ошибка: %1$s</string> <string name="error">Ошибка: %1$s</string>
<string name="error_no_document">Документ не обнаружен</string> <string name="error_no_document">Документ не обнаружен</string>
@@ -33,7 +34,7 @@
<string name="new_document_warning">Результаты текущего сканирования будут потеряны. Желаете продолжить?</string> <string name="new_document_warning">Результаты текущего сканирования будут потеряны. Желаете продолжить?</string>
<string name="open">Открыть</string> <string name="open">Открыть</string>
<string name="open_pdf">Открыть PDF</string> <string name="open_pdf">Открыть PDF</string>
<string name="pdf_saved_to">PDF сохранен в Download</string> <string name="pdf_saved_to">PDF сохранен в %1s</string>
<string name="resume">Продолжить</string> <string name="resume">Продолжить</string>
<string name="save">Сохранить</string> <string name="save">Сохранить</string>
<string name="scan_button">Начать</string> <string name="scan_button">Начать</string>

View File

@@ -15,6 +15,7 @@
<string name="delete_page_warning">是否要删除此页面?</string> <string name="delete_page_warning">是否要删除此页面?</string>
<string name="developer">开发者</string> <string name="developer">开发者</string>
<string name="discard_scan">放弃扫描</string> <string name="discard_scan">放弃扫描</string>
<string name="download_dirname">下载</string>
<string name="end_scan">结束扫描</string> <string name="end_scan">结束扫描</string>
<string name="error">错误: %1$s</string> <string name="error">错误: %1$s</string>
<string name="error_no_document">未检测到任何文档</string> <string name="error_no_document">未检测到任何文档</string>
@@ -33,7 +34,7 @@
<string name="new_document_warning">当前扫描将丢失。是否继续?</string> <string name="new_document_warning">当前扫描将丢失。是否继续?</string>
<string name="open">打开</string> <string name="open">打开</string>
<string name="open_pdf">打开 PDF</string> <string name="open_pdf">打开 PDF</string>
<string name="pdf_saved_to">PDF 保存到</string> <string name="pdf_saved_to">PDF 保存到 %1$s</string>
<string name="resume">恢复</string> <string name="resume">恢复</string>
<string name="save">保存</string> <string name="save">保存</string>
<string name="scan_button">新建扫描</string> <string name="scan_button">新建扫描</string>

View File

@@ -16,6 +16,7 @@
<string name="delete_page_warning">Do you want to delete this page?</string> <string name="delete_page_warning">Do you want to delete this page?</string>
<string name="developer">Developer</string> <string name="developer">Developer</string>
<string name="discard_scan">Discard scan</string> <string name="discard_scan">Discard scan</string>
<string name="download_dirname">Downloads</string>
<string name="end_scan">End scan</string> <string name="end_scan">End scan</string>
<string name="error">Error: %1$s</string> <string name="error">Error: %1$s</string>
<string name="error_no_document">No document detected</string> <string name="error_no_document">No document detected</string>
@@ -34,7 +35,7 @@
<string name="new_document_warning">The current scan will be lost. Do you want to continue?</string> <string name="new_document_warning">The current scan will be lost. Do you want to continue?</string>
<string name="open">Open</string> <string name="open">Open</string>
<string name="open_pdf">Open PDF</string> <string name="open_pdf">Open PDF</string>
<string name="pdf_saved_to">PDF saved in Downloads</string> <string name="pdf_saved_to">PDF saved in %1s</string>
<string name="resume">Resume</string> <string name="resume">Resume</string>
<string name="save">Save</string> <string name="save">Save</string>
<string name="scan_button">New Scan</string> <string name="scan_button">New Scan</string>

View File

@@ -11,6 +11,7 @@ activityCompose = "1.10.1"
composeBom = "2025.08.01" composeBom = "2025.08.01"
camerax = "1.4.2" camerax = "1.4.2"
datastore = "1.2.0" datastore = "1.2.0"
documentfile = "1.1.0"
litert = "1.4.0" litert = "1.4.0"
opencv = "4.12.0" opencv = "4.12.0"
assertj = "3.27.4" assertj = "3.27.4"
@@ -47,6 +48,7 @@ androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycl
androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "camerax" } androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "camerax" }
androidx-datastore = { group = "androidx.datastore", name = "datastore" , version.ref = "datastore" } androidx-datastore = { group = "androidx.datastore", name = "datastore" , version.ref = "datastore" }
androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences" , version.ref = "datastore" } androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences" , version.ref = "datastore" }
androidx-documentfile = { group = "androidx.documentfile", name = "documentfile" , version.ref = "documentfile" }
protobuf-javalite = { group = "com.google.protobuf", name="protobuf-javalite", version.ref = "protobufJavaLite"} protobuf-javalite = { group = "com.google.protobuf", name="protobuf-javalite", version.ref = "protobufJavaLite"}
litert = { group = "com.google.ai.edge.litert", name = "litert", version.ref = "litert" } litert = { group = "com.google.ai.edge.litert", name = "litert", version.ref = "litert" }
litert-support = { group = "com.google.ai.edge.litert", name = "litert-support", version.ref = "litert" } litert-support = { group = "com.google.ai.edge.litert", name = "litert-support", version.ref = "litert" }