mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
Merge pull request #4176 from kiwix/Fixes#4175
Fixed: The ZIM file was displayed on the library screen but failed to open (the ZIM file was located in the SD card's trash folder).
This commit is contained in:
commit
bff8a97055
@ -20,6 +20,7 @@ package eu.mhutti1.utils.storage
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -52,7 +53,9 @@ object StorageDeviceUtils {
|
||||
// In the Play Store variant, we can only access app-specific directories,
|
||||
// so scanning other directories is unnecessary, wastes resources,
|
||||
// and increases the scanning time.
|
||||
if (sharedPreferenceUtil?.isNotPlayStoreBuildWithAndroid11OrAbove() == true) {
|
||||
if (sharedPreferenceUtil?.isPlayStoreBuild == false ||
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.R
|
||||
) {
|
||||
addAll(externalMountPointDevices())
|
||||
addAll(externalFilesDirsDevices(context, false))
|
||||
}
|
||||
|
@ -55,7 +55,10 @@ class NewBookDao @Inject constructor(private val box: Box<BookOnDiskEntity>) {
|
||||
.toList()
|
||||
.toFlowable()
|
||||
.flatMap { booksList ->
|
||||
completableFromCoroutine { removeBooksThatDoNotExist(booksList.toMutableList()) }
|
||||
completableFromCoroutine {
|
||||
removeBooksThatAreInTrashFolder(booksList)
|
||||
removeBooksThatDoNotExist(booksList.toMutableList())
|
||||
}
|
||||
.andThen(io.reactivex.rxjava3.core.Flowable.just(booksList))
|
||||
}
|
||||
}
|
||||
@ -68,7 +71,9 @@ class NewBookDao @Inject constructor(private val box: Box<BookOnDiskEntity>) {
|
||||
bookOnDiskEntity to exists
|
||||
}
|
||||
}
|
||||
.filter(Pair<BookOnDiskEntity, Boolean>::second)
|
||||
.filter { (bookOnDiskEntity, exists) ->
|
||||
exists && !isInTrashFolder(bookOnDiskEntity.zimReaderSource.toDatabase())
|
||||
}
|
||||
.map(Pair<BookOnDiskEntity, Boolean>::first)
|
||||
.toList()
|
||||
.toFlowable()
|
||||
@ -150,6 +155,15 @@ class NewBookDao @Inject constructor(private val box: Box<BookOnDiskEntity>) {
|
||||
delete(books.filterNot { it.zimReaderSource.exists() })
|
||||
}
|
||||
|
||||
// Remove the existing books from database which are showing on the library screen.
|
||||
private fun removeBooksThatAreInTrashFolder(books: List<BookOnDiskEntity>) {
|
||||
delete(books.filter { isInTrashFolder(it.zimReaderSource.toDatabase()) })
|
||||
}
|
||||
|
||||
// Check if any existing ZIM file showing on the library screen which is inside the trash folder.
|
||||
private fun isInTrashFolder(filePath: String) =
|
||||
Regex("/\\.Trash/").containsMatchIn(filePath)
|
||||
|
||||
private fun delete(books: List<BookOnDiskEntity>) {
|
||||
box.remove(books)
|
||||
}
|
||||
|
@ -48,11 +48,16 @@ class FileSearch @Inject constructor(private val context: Context) {
|
||||
private fun scanMediaStore() = mutableListOf<File>().apply {
|
||||
queryMediaStore()
|
||||
?.forEachRow { cursor ->
|
||||
File(cursor.get<String>(MediaColumns.DATA)).takeIf(File::canRead)
|
||||
?.also { add(it) }
|
||||
File(cursor.get<String>(MediaColumns.DATA))
|
||||
.takeIf { it.canRead() && isNotInTrashFolder(it) }
|
||||
?.also(::add)
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude any file in trash folder.
|
||||
private fun isNotInTrashFolder(it: File) =
|
||||
!Regex("/\\.Trash/").containsMatchIn(it.path)
|
||||
|
||||
private fun queryMediaStore() = context.contentResolver
|
||||
.query(
|
||||
Files.getContentUri("external"),
|
||||
@ -86,8 +91,8 @@ class FileSearch @Inject constructor(private val context: Context) {
|
||||
private fun scanDirectory(directory: String): List<File> {
|
||||
return File(directory).walk()
|
||||
.onEnter { dir ->
|
||||
// Excluding the "data," "obb," and "Trash" folders from scanning is justified for
|
||||
// several reasons. The "Trash" folder contains deleted files,
|
||||
// Excluding the "data," "obb," "hidden folders," and "Trash" folders from scanning is
|
||||
// justified for several reasons. The "Trash" folder contains deleted files,
|
||||
// making it unnecessary for scanning. Additionally,
|
||||
// the "data" and "obb" folders are specifically designed for the
|
||||
// app's private directory, and users usually do not store ZIM files there.
|
||||
@ -97,7 +102,8 @@ class FileSearch @Inject constructor(private val context: Context) {
|
||||
// which are irrelevant to our application.
|
||||
!dir.name.equals(".Trash", ignoreCase = true) &&
|
||||
!dir.name.equals("data", ignoreCase = true) &&
|
||||
!dir.name.equals("obb", ignoreCase = true)
|
||||
!dir.name.equals("obb", ignoreCase = true) &&
|
||||
!dir.name.startsWith(".", ignoreCase = true)
|
||||
}.filter {
|
||||
it.extension.isAny(*zimFileExtensions)
|
||||
}.toList()
|
||||
|
@ -81,7 +81,17 @@ internal class NewBookDaoTest {
|
||||
verify { box.remove(listOf(deletedEntity)) }
|
||||
}
|
||||
|
||||
private fun expectEmissionOfExistingAndNotExistingBook():
|
||||
@Test
|
||||
fun `books removes entities whose files are in the trash folder`() {
|
||||
runBlocking {
|
||||
val (_, _) = expectEmissionOfExistingAndNotExistingBook(true)
|
||||
val books = newBookDao.books().test()
|
||||
delay(1000)
|
||||
books.assertValues(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun expectEmissionOfExistingAndNotExistingBook(isInTrashFolder: Boolean = false):
|
||||
Pair<BookOnDiskEntity, BookOnDiskEntity> {
|
||||
val query: Query<BookOnDiskEntity> = mockk()
|
||||
every { box.query().build() } returns query
|
||||
@ -89,6 +99,10 @@ internal class NewBookDaoTest {
|
||||
val zimReaderSourceThatDoesNotExist = mockk<ZimReaderSource>()
|
||||
coEvery { zimReaderSourceThatExists.exists() } returns true
|
||||
coEvery { zimReaderSourceThatDoesNotExist.exists() } returns false
|
||||
every {
|
||||
zimReaderSourceThatExists.toDatabase()
|
||||
} returns if (isInTrashFolder) "/.Trash/test.zim" else ""
|
||||
every { zimReaderSourceThatDoesNotExist.toDatabase() } returns ""
|
||||
val entityThatExists = bookOnDiskEntity(zimReaderSource = zimReaderSourceThatExists)
|
||||
val entityThatDoesNotExist =
|
||||
bookOnDiskEntity(zimReaderSource = zimReaderSourceThatDoesNotExist)
|
||||
|
Loading…
x
Reference in New Issue
Block a user