Skip to content

Commit

Permalink
Merge pull request #4176 from kiwix/Fixes#4175
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
kelson42 authored Jan 16, 2025
2 parents 283d845 + 8ded3d3 commit bff8a97
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
}
Expand Down
18 changes: 16 additions & 2 deletions core/src/main/java/org/kiwix/kiwixmobile/core/dao/NewBookDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}
Expand All @@ -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()
Expand Down Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -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.
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,28 @@ 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
val zimReaderSourceThatExists = mockk<ZimReaderSource>()
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)
Expand Down

0 comments on commit bff8a97

Please sign in to comment.