#1173 Do not filter out files over 4GB when storage is fat32, Grey them out instead

This commit is contained in:
Sean Mac Gillicuddy 2019-12-06 10:28:42 +00:00
parent d7834e7da4
commit 30827d5815
6 changed files with 214 additions and 114 deletions

View File

@ -32,6 +32,7 @@ import io.reactivex.processors.PublishProcessor
import io.reactivex.schedulers.Schedulers
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.StorageObserver
import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.dao.FetchDownloadDao
import org.kiwix.kiwixmobile.core.dao.NewBookDao
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
@ -50,10 +51,6 @@ import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode.NORM
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.CanWrite4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.CannotWrite4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.NotEnoughSpaceFor4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.Unknown
import org.kiwix.kiwixmobile.zim_manager.NetworkState.CONNECTED
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.MultiModeFinished
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.RequestDeleteMultiSelection
@ -66,7 +63,6 @@ import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.DeleteFiles
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.None
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.OpenFile
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.ShareFiles
import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.StartMultiSelection
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.BookItem
@ -354,14 +350,6 @@ class ZimManageViewModel @Inject constructor(
val booksUnfilteredByLanguage =
applyUserFilter(
libraryNetworkEntity.books
.filter {
when (fileSystemState) {
Unknown,
CannotWrite4GbFile -> isLessThan4GB(it)
NotEnoughSpaceFor4GbFile,
CanWrite4GbFile -> true
}
}
.filterNot { downloadedBooksIds.contains(it.id) }
.filterNot { downloadingBookIds.contains(it.id) },
filter
@ -370,30 +358,29 @@ class ZimManageViewModel @Inject constructor(
return listOf(
*createLibrarySection(
booksUnfilteredByLanguage.filter { activeLanguageCodes.contains(it.language) },
fileSystemState,
R.string.your_languages,
Long.MAX_VALUE
),
*createLibrarySection(
booksUnfilteredByLanguage.filterNot { activeLanguageCodes.contains(it.language) },
fileSystemState,
R.string.other_languages,
Long.MIN_VALUE
)
)
}
private fun isLessThan4GB(it: Book) =
it.size.toLongOrNull() ?: 0L <
Fat32Checker.FOUR_GIGABYTES_IN_KILOBYTES
private fun createLibrarySection(
books: List<Book>,
fileSystemState: FileSystemState,
sectionStringId: Int,
sectionId: Long
) =
if (books.isNotEmpty())
arrayOf(
DividerItem(sectionId, context.getString(sectionStringId)),
*toBookItems(books)
*toBookItems(books, fileSystemState)
)
else emptyArray()
@ -407,8 +394,11 @@ class ZimManageViewModel @Inject constructor(
booksUnfilteredByLanguage.filter { it.searchMatches > 0 }
}
private fun toBookItems(books: List<Book>) =
books.map { BookItem(it) }.toTypedArray()
private fun toBookItems(
books: List<Book>,
fileSystemState: FileSystemState
) =
books.map { BookItem(it, fileSystemState) }.toTypedArray()
private fun checkFileSystemForBooksOnRequest(booksFromDao: Flowable<List<BookOnDisk>>) =
requestFileSystemCheck

View File

@ -19,6 +19,12 @@
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.CanWrite4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.CannotWrite4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.NotEnoughSpaceFor4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.Unknown
sealed class LibraryListItem {
abstract val id: Long
@ -28,8 +34,22 @@ sealed class LibraryListItem {
val text: String
) : LibraryListItem()
data class BookItem(
data class BookItem constructor(
val book: Book,
val canBeDownloaded: Boolean,
override val id: Long = book.id.hashCode().toLong()
) : LibraryListItem()
) : LibraryListItem() {
constructor(book: Book, fileSystemState: FileSystemState) : this(
book,
when (fileSystemState) {
Unknown, CannotWrite4GbFile -> book.isLessThan4GB()
NotEnoughSpaceFor4GbFile, CanWrite4GbFile -> true
}
)
companion object {
private fun Book.isLessThan4GB() =
size.toLongOrNull() ?: 0L < Fat32Checker.FOUR_GIGABYTES_IN_KILOBYTES
}
}
}

View File

@ -19,7 +19,6 @@
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
import android.view.View
import kotlinx.android.synthetic.main.library_divider.divider_text
import kotlinx.android.synthetic.main.item_library.creator
import kotlinx.android.synthetic.main.item_library.date
import kotlinx.android.synthetic.main.item_library.description
@ -29,14 +28,16 @@ import kotlinx.android.synthetic.main.item_library.language
import kotlinx.android.synthetic.main.item_library.publisher
import kotlinx.android.synthetic.main.item_library.size
import kotlinx.android.synthetic.main.item_library.title
import kotlinx.android.synthetic.main.item_library.unableToDownload
import kotlinx.android.synthetic.main.library_divider.divider_text
import org.kiwix.kiwixmobile.core.CoreApp
import org.kiwix.kiwixmobile.core.base.adapter.BaseViewHolder
import org.kiwix.kiwixmobile.core.downloader.model.Base64String
import org.kiwix.kiwixmobile.core.extensions.setBitmap
import org.kiwix.kiwixmobile.core.extensions.setTextAndVisibility
import org.kiwix.kiwixmobile.core.utils.BookUtils
import org.kiwix.kiwixmobile.core.utils.NetworkUtils
import org.kiwix.kiwixmobile.core.zim_manager.KiloByte
import org.kiwix.kiwixmobile.core.base.adapter.BaseViewHolder
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.BookItem
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.DividerItem
@ -64,6 +65,8 @@ sealed class LibraryViewHolder<in T : LibraryListItem>(containerView: View) :
containerView.setOnClickListener {
clickAction.invoke(item)
}
unableToDownload.setOnTouchListener { _, _ -> true }
unableToDownload.visibility = if (item.canBeDownloaded) View.GONE else View.VISIBLE
}
}

View File

@ -1,115 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:minHeight="?listPreferredItemHeight"
android:orientation="horizontal"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:ignore="Overdraw">
tools:ignore="Overdraw, RTLHardcoded">
<ImageView
android:id="@+id/favicon"
android:layout_width="@dimen/favicon_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/favicon_margin_right"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlHardcoded" />
<LinearLayout
android:layout_width="0dp"
<TextView
android:id="@+id/title"
style="@style/list_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="@dimen/dimen_small_padding"
tools:ignore="RtlHardcoded,RtlSymmetry">
android:layout_marginLeft="@dimen/favicon_margin_right"
android:layout_marginTop="@dimen/activity_horizontal_margin"
app:layout_constraintStart_toEndOf="@+id/favicon"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title" />
<TextView
android:id="@+id/title"
style="@style/list_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Title" />
<TextView
android:id="@+id/description"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/title"
app:layout_constraintTop_toBottomOf="@+id/title"
tools:text="Description" />
<TextView
android:id="@+id/description"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Description" />
<TextView
android:id="@+id/size"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/description"
app:layout_constraintTop_toBottomOf="@+id/description"
tools:text="File Size" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingTop="@dimen/dimen_medium_padding">
<TextView
android:id="@+id/creator"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/size"
app:layout_constraintTop_toBottomOf="@+id/size"
tools:text="Author" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/publisher"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_horizontal_margin"
app:layout_constraintStart_toStartOf="@+id/creator"
app:layout_constraintTop_toBottomOf="@+id/creator"
tools:text="Publisher" />
<TextView
android:id="@+id/size"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="File Size" />
<TextView
android:id="@+id/creator"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Author" />
<TextView
android:id="@+id/date"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/activity_horizontal_margin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/size"
tools:text="Date" />
<TextView
android:id="@+id/publisher"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Publisher" />
<TextView
android:id="@+id/language"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@+id/date"
app:layout_constraintTop_toBottomOf="@+id/date"
tools:text="Language" />
</LinearLayout>
<TextView
android:id="@+id/fileName"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@+id/language"
app:layout_constraintTop_toBottomOf="@+id/language"
tools:text="File Name" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="end"
android:orientation="vertical">
<View
android:id="@+id/unableToDownload"
android:layout_width="0dp"
android:layout_height="0dp"
android:alpha=".5"
android:background="#808080"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="gone" />
<TextView
android:id="@+id/date"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Date" />
<TextView
android:id="@+id/language"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Language" />
<TextView
android:id="@+id/fileName"
style="@style/list_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="File Name" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -392,15 +392,16 @@ class ZimManageViewModelTest {
.assertValue(
listOf(
LibraryListItem.DividerItem(Long.MAX_VALUE, "1"),
LibraryListItem.BookItem(bookWithActiveLanguage),
LibraryListItem.BookItem(bookWithActiveLanguage, true),
LibraryListItem.DividerItem(Long.MIN_VALUE, "2"),
LibraryListItem.BookItem(bookWithInactiveLanguage)
LibraryListItem.BookItem(bookWithInactiveLanguage, true)
)
)
}
@Test
fun `library filters out files over 4GB if file system state says to`() {
fun `library marks files over 4GB as can't download if file system state says to`() {
every { application.getString(R.string.other_languages) } returns "2"
val bookOver4Gb = book(
id = "0",
url = "",
@ -423,6 +424,11 @@ class ZimManageViewModelTest {
testScheduler.advanceTimeBy(500, MILLISECONDS)
testScheduler.triggerActions()
viewModel.libraryItems.test()
.assertValue(listOf())
.assertValue(
listOf(
LibraryListItem.DividerItem(Long.MIN_VALUE, "2"),
LibraryListItem.BookItem(bookOver4Gb, false)
)
)
}
}

View File

@ -0,0 +1,81 @@
/*
* Kiwix Android
* Copyright (c) 2019 Kiwix <android.kiwix.org>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
import io.mockk.clearAllMocks
import io.mockk.every
import io.mockk.mockk
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.CanWrite4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.CannotWrite4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.NotEnoughSpaceFor4GbFile
import org.kiwix.kiwixmobile.zim_manager.Fat32Checker.FileSystemState.Unknown
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.BookItem
internal class LibraryListItemTest {
val book = mockk<Book>()
@BeforeEach
fun init() {
clearAllMocks()
every { book.getId() } returns "0"
every { book.getSize() } returns "0"
}
@Test
internal fun `Unknown file system state files under 4GB can be downloaded`() {
assertThat(canBeDownloaded(book, Unknown)).isTrue()
}
@Test
internal fun `Unknown file system state greater than 4GB can't be downloaded`() {
every { book.getSize() } returns (Fat32Checker.FOUR_GIGABYTES_IN_KILOBYTES + 1).toString()
assertThat(canBeDownloaded(book, Unknown)).isFalse()
}
@Test
internal fun `Unknown file system state empty size can be downloaded`() {
every { book.getSize() } returns ""
assertThat(canBeDownloaded(book, Unknown)).isTrue()
}
@Test
internal fun `CannotWrite4GB file system state can be downloaded`() {
assertThat(canBeDownloaded(book, CannotWrite4GbFile)).isTrue()
}
@Test
internal fun `CanWrite4GbFile file system state can be downloaded`() {
assertThat(canBeDownloaded(book, CanWrite4GbFile)).isTrue()
}
@Test
internal fun `NotEnoughSpaceFor4GbFile file system state can be downloaded`() {
assertThat(canBeDownloaded(book, NotEnoughSpaceFor4GbFile)).isTrue()
}
private fun canBeDownloaded(book: Book, fileSystemState: FileSystemState) =
BookItem(book, fileSystemState).canBeDownloaded
}