Skip to content

Commit

Permalink
Merge pull request #3972 from kiwix/Fixes#3970
Browse files Browse the repository at this point in the history
Removed the dialog box to select the storage in settings.
  • Loading branch information
kelson42 authored Aug 8, 2024
2 parents 5a58800 + 65297a7 commit a6de67e
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class DeepLinksTest : BaseActivityTest() {
private fun loadZimFileInApplicationAndReturnSchemeTypeUri(schemeType: String): Uri? {
val loadFileStream =
DeepLinksTest::class.java.classLoader.getResourceAsStream("testzim.zim")
val zimFile = File(sharedPreferenceUtil.prefStorage, "testzim.zim")
val zimFile = File(sharedPreferenceUtil.defaultStorage(), "testzim.zim")
if (zimFile.exists()) zimFile.delete()
zimFile.createNewFile()
loadFileStream.use { inputStream ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ class KiwixSettingsFragmentTest {
handleLocaleChange(
it,
"en",
SharedPreferenceUtil(it)
SharedPreferenceUtil(it).apply {
setIsPlayStoreBuildType(true)
}
)
it.navigate(R.id.introFragment)
}
Expand All @@ -101,9 +103,8 @@ class KiwixSettingsFragmentTest {
toggleOpenNewTabInBackground()
toggleExternalLinkWarningPref()
toggleWifiDownloadsOnlyPref()
clickStoragePreference()
assertStorageDialogDisplayed()
dismissDialog()
clickExternalStoragePreference()
clickInternalStoragePreference()
clickClearHistoryPreference()
assertHistoryDialogDisplayed()
dismissDialog()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
import androidx.test.espresso.matcher.ViewMatchers.withSubstring
import androidx.test.espresso.matcher.ViewMatchers.withText
import applyWithViewHierarchyPrinting
import org.hamcrest.Matchers
Expand All @@ -36,6 +37,7 @@ import org.kiwix.kiwixmobile.BaseRobot
import org.kiwix.kiwixmobile.Findable.StringId.TextId
import org.kiwix.kiwixmobile.Findable.Text
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.testutils.TestUtils.getResourceString
import org.kiwix.kiwixmobile.testutils.TestUtils.testFlakyView

/**
Expand All @@ -61,6 +63,16 @@ class SettingsRobot : BaseRobot() {
)
}

private fun clickRecyclerViewItemsContainingText(@StringRes vararg stringIds: Int) {
onView(
withResourceName("recycler_view")
).perform(
actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(Matchers.anyOf(*stringIds.subStringMatchers())), ViewActions.click()
)
)
}

fun toggleBackToTopPref() {
clickRecyclerViewItems(R.string.pref_back_to_top)
}
Expand Down Expand Up @@ -100,12 +112,12 @@ class SettingsRobot : BaseRobot() {
isVisible(TextId(R.string.pref_language_title))
}

fun clickStoragePreference() {
clickRecyclerViewItems(R.string.internal_storage, R.string.external_storage)
fun clickInternalStoragePreference() {
clickRecyclerViewItemsContainingText(R.string.internal_storage)
}

fun assertStorageDialogDisplayed() {
isVisible(TextId(R.string.pref_storage))
fun clickExternalStoragePreference() {
clickRecyclerViewItemsContainingText(R.string.external_storage)
}

fun clickClearHistoryPreference() {
Expand Down Expand Up @@ -181,4 +193,7 @@ class SettingsRobot : BaseRobot() {
context.resources.getStringArray(R.array.pref_dark_modes_entries)

private fun IntArray.matchers() = map(::withText).toTypedArray()
private fun IntArray.subStringMatchers() = map {
withSubstring(getResourceString(it))
}.toTypedArray()
}
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class ZimHostFragmentTest {
private fun loadZimFileInApplication(zimFileName: String) {
val loadFileStream =
ZimHostFragmentTest::class.java.classLoader.getResourceAsStream(zimFileName)
val zimFile = File(sharedPreferenceUtil.prefStorage, zimFileName)
val zimFile = File(sharedPreferenceUtil.defaultStorage(), zimFileName)
if (zimFile.exists()) zimFile.delete()
zimFile.createNewFile()
loadFileStream.use { inputStream ->
Expand Down
125 changes: 109 additions & 16 deletions app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,26 @@ package org.kiwix.kiwixmobile.settings
import android.os.Build
import android.os.Bundle
import android.os.Environment
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.kiwix.kiwixmobile.R
import eu.mhutti1.utils.storage.StorageDevice
import eu.mhutti1.utils.storage.StorageDeviceUtils
import io.reactivex.Flowable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.navigateToSettings
import org.kiwix.kiwixmobile.core.settings.CorePrefsFragment
import org.kiwix.kiwixmobile.core.settings.StorageRadioButtonPreference
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil.Companion.PREF_STORAGE
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil.Companion.PREF_EXTERNAL_STORAGE
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil.Companion.PREF_INTERNAL_STORAGE

class KiwixPrefsFragment : CorePrefsFragment() {
private var storageDisposable: Disposable? = null
private var storageDeviceList: List<StorageDevice> = listOf()

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
super.onCreatePreferences(savedInstanceState, rootKey)
Expand All @@ -44,20 +50,102 @@ class KiwixPrefsFragment : CorePrefsFragment() {

override fun setStorage() {
sharedPreferenceUtil?.let {
val internalStorage = runBlocking { internalStorage() }
findPreference<Preference>(PREF_STORAGE)?.title = getString(
if (it.prefStorage == internalStorage?.let(
it::getPublicDirectoryPath
if (storageDisposable?.isDisposed == false) {
// update the storage when user switch to other storage.
setUpStoragePreference(it)
}
storageDisposable =
Flowable.fromCallable { StorageDeviceUtils.getWritableStorage(requireActivity()) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ storageList ->
storageDeviceList = storageList
showExternalPreferenceIfAvailable()
setUpStoragePreference(it)
},
Throwable::printStackTrace
)
) R.string.internal_storage
else R.string.external_storage
)
}
findPreference<Preference>(PREF_STORAGE)?.summary = storageCalculator?.calculateAvailableSpace()
}

private suspend fun internalStorage(): String? = withContext(Dispatchers.IO) {
ContextCompat.getExternalFilesDirs(requireContext(), null).firstOrNull()?.path
private fun setUpStoragePreference(sharedPreferenceUtil: SharedPreferenceUtil) {
storageDeviceList.forEachIndexed { index, storageDevice ->
val preferenceKey = if (index == 0) PREF_INTERNAL_STORAGE else PREF_EXTERNAL_STORAGE
val selectedStoragePosition = sharedPreferenceUtil.storagePosition
val isChecked = selectedStoragePosition == index
findPreference<StorageRadioButtonPreference>(preferenceKey)?.apply {
this.isChecked = isChecked
setOnPreferenceClickListener {
onStorageDeviceSelected(storageDevice)
true
}
setPathAndTitleForStorage(
buildStoragePathAndTitle(
storageDevice,
index,
selectedStoragePosition,
sharedPreferenceUtil
)
)
setFreeSpace(getFreeSpaceText(storageDevice))
setUsedSpace(getUsedSpaceText(storageDevice))
setProgress(calculateUsedPercentage(storageDevice))
}
}
}

private fun getFreeSpaceText(storageDevice: StorageDevice): String {
val freeSpace = storageCalculator?.calculateAvailableSpace(storageDevice.file)
return getString(R.string.pref_free_storage, freeSpace)
}

private fun getUsedSpaceText(storageDevice: StorageDevice): String {
val usedSpace = storageCalculator?.calculateUsedSpace(storageDevice.file)
return getString(R.string.pref_storage_used, usedSpace)
}

private fun buildStoragePathAndTitle(
storageDevice: StorageDevice,
index: Int,
selectedStoragePosition: Int,
sharedPreferenceUtil: SharedPreferenceUtil
): String {
val storageName = if (storageDevice.isInternal) {
getString(R.string.internal_storage)
} else {
getString(R.string.external_storage)
}
val storagePath = if (index == selectedStoragePosition) {
sharedPreferenceUtil.prefStorage
} else {
getStoragePathForNonSelectedStorage(storageDevice, sharedPreferenceUtil)
}
val totalSpace = storageCalculator?.calculateTotalSpace(storageDevice.file)
return "$storageName - $totalSpace\n$storagePath/Kiwix"
}

private fun getStoragePathForNonSelectedStorage(
storageDevice: StorageDevice,
sharedPreferenceUtil: SharedPreferenceUtil
): String =
if (storageDevice.isInternal) {
sharedPreferenceUtil.getPublicDirectoryPath(storageDevice.name)
} else {
storageDevice.name
}

@Suppress("MagicNumber")
private fun calculateUsedPercentage(storageDevice: StorageDevice): Int {
val totalSpace = storageCalculator?.totalBytes(storageDevice.file) ?: 1
val availableSpace = storageCalculator?.availableBytes(storageDevice.file) ?: 0
val usedSpace = totalSpace - availableSpace
return (usedSpace.toDouble() / totalSpace * 100).toInt()
}

private fun showExternalPreferenceIfAvailable() {
findPreference<StorageRadioButtonPreference>(PREF_EXTERNAL_STORAGE)?.isVisible =
storageDeviceList.size > 1
}

private fun setMangeExternalStoragePermission() {
Expand Down Expand Up @@ -87,6 +175,11 @@ class KiwixPrefsFragment : CorePrefsFragment() {
preferenceCategory?.isVisible = true
}

override fun onDestroyView() {
storageDisposable?.dispose()
super.onDestroyView()
}

companion object {
const val PREF_MANAGE_EXTERNAL_STORAGE_PERMISSION =
"pref_manage_external_storage"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.snackbar.Snackbar
import eu.mhutti1.utils.storage.StorageDevice
import eu.mhutti1.utils.storage.StorageSelectDialog
import org.kiwix.kiwixmobile.core.CoreApp.Companion.coreComponent
import org.kiwix.kiwixmobile.core.CoreApp.Companion.instance
import org.kiwix.kiwixmobile.core.DarkModeConfig
Expand Down Expand Up @@ -301,9 +300,6 @@ abstract class CorePrefsFragment :
if (preference.key.equals(PREF_CREDITS, ignoreCase = true)) {
openCredits()
}
if (preference.key.equals(SharedPreferenceUtil.PREF_STORAGE, ignoreCase = true)) {
openFolderSelect()
}
if (preference.key.equals(PREF_EXPORT_BOOKMARK, ignoreCase = true) &&
requestExternalStorageWritePermissionForExportBookmark()
) {
Expand Down Expand Up @@ -447,29 +443,18 @@ abstract class CorePrefsFragment :
private fun isValidBookmarkFile(mimeType: String?) =
mimeType == "application/xml" || mimeType == "text/xml"

private fun openFolderSelect() {
val dialogFragment = StorageSelectDialog()
dialogFragment.onSelectAction =
::onStorageDeviceSelected
dialogFragment.show(
requireActivity().supportFragmentManager,
resources.getString(R.string.pref_storage)
)
}

@Suppress("NestedBlockDepth")
private fun onStorageDeviceSelected(storageDevice: StorageDevice) {
fun onStorageDeviceSelected(storageDevice: StorageDevice) {
sharedPreferenceUtil?.let { sharedPreferenceUtil ->
findPreference<Preference>(SharedPreferenceUtil.PREF_STORAGE)?.summary =
storageCalculator?.calculateAvailableSpace(storageDevice.file)
if (storageDevice.isInternal) {
sharedPreferenceUtil.putPrefStorage(
sharedPreferenceUtil.getPublicDirectoryPath(storageDevice.name)
)
findPreference<Preference>(SharedPreferenceUtil.PREF_STORAGE)?.title =
getString(R.string.internal_storage)
sharedPreferenceUtil.putStoragePosition(INTERNAL_SELECT_POSITION)
setShowStorageOption()
setStorage()
} else {
if (sharedPreferenceUtil.isPlayStoreBuild) {
setExternalStoragePath(storageDevice)
Expand All @@ -492,10 +477,9 @@ abstract class CorePrefsFragment :

private fun setExternalStoragePath(storageDevice: StorageDevice) {
sharedPreferenceUtil?.putPrefStorage(storageDevice.name)
findPreference<Preference>(SharedPreferenceUtil.PREF_STORAGE)?.title =
getString(R.string.external_storage)
sharedPreferenceUtil?.putStoragePosition(EXTERNAL_SELECT_POSITION)
setShowStorageOption()
setStorage()
}

private fun selectFolder() {
Expand All @@ -516,10 +500,9 @@ abstract class CorePrefsFragment :
result.data?.let { intent ->
getPathFromUri(requireActivity(), intent)?.let { path ->
sharedPreferenceUtil?.putPrefStorage(path)
findPreference<Preference>(SharedPreferenceUtil.PREF_STORAGE)?.title =
getString(R.string.external_storage)
sharedPreferenceUtil?.putStoragePosition(EXTERNAL_SELECT_POSITION)
setShowStorageOption()
setStorage()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ class StorageCalculator @Inject constructor(
fun calculateTotalSpace(file: File = File(sharedPreferenceUtil.prefStorage)): String =
Bytes(totalBytes(file)).humanReadable

fun calculateUsedSpace(file: File): String =
Bytes(totalBytes(file) - availableBytes(file)).humanReadable

fun availableBytes(file: File = File(sharedPreferenceUtil.prefStorage)) =
if (file.isFileExist()) file.freeSpace()
else 0L

private fun totalBytes(file: File) = if (file.isFileExist()) file.totalSpace() else 0L
fun totalBytes(file: File) = if (file.isFileExist()) file.totalSpace() else 0L
}
Loading

0 comments on commit a6de67e

Please sign in to comment.