Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removed the dialog box to select the storage in settings. #3972

Merged
merged 7 commits into from
Aug 8, 2024
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 @@
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 @@

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)

Check warning on line 55 in app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt#L55

Added line #L55 was not covered by tests
}
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 @@
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.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 @@
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 @@
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 @@

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 @@
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()

Check warning on line 505 in core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.kt

View check run for this annotation

Codecov / codecov/patch

core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.kt#L505

Added line #L505 was not covered by tests
}
}
}
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
Loading