From d2114569962bdeb92583852e862b8a302378a84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C9=91rry=20Shiv=C9=91m?= Date: Sat, 1 Jun 2024 10:45:33 +0530 Subject: [PATCH] Revert "Add ability to import multiple epubs at once (#179)" This reverts commit ec3a9af5a5b402e03a3ace25d2186d4b2d857470. --- .../library/composables/LibraryScreen.kt | 60 ++++++++------- .../library/viewmodels/LibraryViewModel.kt | 73 +++++++------------ 2 files changed, 57 insertions(+), 76 deletions(-) diff --git a/app/src/main/java/com/starry/myne/ui/screens/library/composables/LibraryScreen.kt b/app/src/main/java/com/starry/myne/ui/screens/library/composables/LibraryScreen.kt index eaa2042f..e7e0ccf6 100644 --- a/app/src/main/java/com/starry/myne/ui/screens/library/composables/LibraryScreen.kt +++ b/app/src/main/java/com/starry/myne/ui/screens/library/composables/LibraryScreen.kt @@ -117,6 +117,7 @@ import kotlinx.coroutines.launch import me.saket.swipe.SwipeAction import me.saket.swipe.SwipeableActionsBox import java.io.File +import java.io.FileInputStream @OptIn(ExperimentalMaterial3Api::class) @@ -132,38 +133,35 @@ fun LibraryScreen(navController: NavController) { val showImportDialog = remember { mutableStateOf(false) } val importBookLauncher = - rememberLauncherForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { uris -> - // If no files are selected, return. - if (uris.isEmpty()) return@rememberLauncherForActivityResult - // Show dialog to indicate import process. - showImportDialog.value = true - // Start books import. - viewModel.importBooks( - context = context, - fileUris = uris, - onComplete = { - // Hide dialog and show success message. - showImportDialog.value = false - coroutineScope.launch { - snackBarHostState.showSnackbar( - message = context.getString(R.string.epub_imported), - actionLabel = context.getString(R.string.ok), - duration = SnackbarDuration.Short - ) - } - }, - onError = { - // Hide dialog and show error message. - showImportDialog.value = false - coroutineScope.launch { - snackBarHostState.showSnackbar( - message = context.getString(R.string.error), - actionLabel = context.getString(R.string.ok), - duration = SnackbarDuration.Short - ) - } + rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri -> + uri?.let { + (context as MainActivity).contentResolver.openInputStream(uri)?.let { ips -> + showImportDialog.value = true // Show import dialog + viewModel.importBook( + context = context, + fileStream = ips as FileInputStream, + onComplete = { + showImportDialog.value = false + coroutineScope.launch { + snackBarHostState.showSnackbar( + message = context.getString(R.string.epub_imported), + actionLabel = context.getString(R.string.ok), + duration = SnackbarDuration.Short + ) + } + }, + onError = { + showImportDialog.value = false + coroutineScope.launch { + snackBarHostState.showSnackbar( + message = context.getString(R.string.error), + actionLabel = context.getString(R.string.ok), + duration = SnackbarDuration.Short + ) + } + }) } - ) + } } val showTapTargets = remember { mutableStateOf(false) } diff --git a/app/src/main/java/com/starry/myne/ui/screens/library/viewmodels/LibraryViewModel.kt b/app/src/main/java/com/starry/myne/ui/screens/library/viewmodels/LibraryViewModel.kt index 17b3fd2a..4f5f8482 100644 --- a/app/src/main/java/com/starry/myne/ui/screens/library/viewmodels/LibraryViewModel.kt +++ b/app/src/main/java/com/starry/myne/ui/screens/library/viewmodels/LibraryViewModel.kt @@ -17,8 +17,6 @@ package com.starry.myne.ui.screens.library.viewmodels import android.content.Context -import android.net.Uri -import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf @@ -77,58 +75,43 @@ class LibraryViewModel @Inject constructor( _showOnboardingTapTargets.value = false } - fun importBooks( + fun importBook( context: Context, - fileUris: List, + fileStream: FileInputStream, onComplete: () -> Unit, - onError: (Throwable) -> Unit + onError: (Exception) -> Unit ) { viewModelScope.launch(Dispatchers.IO) { - val result = runCatching { - fileUris.forEach { uri -> - context.contentResolver.openInputStream(uri)?.use { fis -> - if (fis !is FileInputStream) { - throw IllegalArgumentException("File input stream is not valid.") - } - - val epubBook = epubParser.createEpubBook(fis) - fis.channel.position(0) - - val filePath = copyBookToInternalStorage( - context, fis, - BookDownloader.createFileName(epubBook.title) - ) - - val libraryItem = LibraryItem( - bookId = 0, - title = epubBook.title, - authors = epubBook.author, - filePath = filePath, - createdAt = System.currentTimeMillis(), - isExternalBook = true - ) - - libraryDao.insert(libraryItem) - } - } - - // Add delay here so user can see the import progress bar even if - // the import is very fast instead of just a flicker, improving UX - delay(800) - } - - withContext(Dispatchers.Main) { - result.onSuccess { - onComplete() - }.onFailure { exception -> - Log.e("LibraryViewModel", "Error importing book", exception) - onError(exception) + try { + fileStream.use { fis -> + val epubBook = epubParser.createEpubBook(fis) + // reset the stream position to 0 so that it can be read again + fis.channel.position(0) + // copy the book to internal storage + val filePath = copyBookToInternalStorage( + context, fis, + BookDownloader.createFileName(epubBook.title) + ) + // insert the book into the database + val libraryItem = LibraryItem( + bookId = 0, + title = epubBook.title, + authors = epubBook.author, + filePath = filePath, + createdAt = System.currentTimeMillis(), + isExternalBook = true + ) + libraryDao.insert(libraryItem) + delay(800) // delay to prevent from flickering. + withContext(Dispatchers.Main) { onComplete() } } + } catch (exc: Exception) { + exc.printStackTrace() + withContext(Dispatchers.Main) { onError(exc) } } } } - private suspend fun copyBookToInternalStorage( context: Context, fileStream: FileInputStream,