diff --git a/app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt index 8e40ca4c7d..cfba5eab5a 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt @@ -22,6 +22,7 @@ import android.os.Build import android.os.Bundle import android.os.Environment import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import androidx.preference.PreferenceCategory import eu.mhutti1.utils.storage.StorageDevice @@ -30,6 +31,7 @@ import io.reactivex.Flowable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.launch import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.extensions.getFreeSpace import org.kiwix.kiwixmobile.core.extensions.getUsedSpace @@ -52,7 +54,7 @@ class KiwixPrefsFragment : CorePrefsFragment() { setMangeExternalStoragePermission() } - override fun setStorage() { + override suspend fun setStorage() { sharedPreferenceUtil?.let { if (storageDisposable?.isDisposed == false) { // update the storage when user switch to other storage. @@ -74,23 +76,25 @@ class KiwixPrefsFragment : CorePrefsFragment() { } 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(preferenceKey)?.apply { - this.isChecked = isChecked - setOnPreferenceClickListener { - onStorageDeviceSelected(storageDevice) - true - } - storageCalculator?.let { - setPathAndTitleForStorage( - storageDevice.storagePathAndTitle(context, index, sharedPreferenceUtil, it) - ) - setFreeSpace(storageDevice.getFreeSpace(context, it)) - setUsedSpace(storageDevice.getUsedSpace(context, it)) - setProgress(storageDevice.usedPercentage(it)) + lifecycleScope.launch { + 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(preferenceKey)?.apply { + this.isChecked = isChecked + setOnPreferenceClickListener { + onStorageDeviceSelected(storageDevice) + true + } + storageCalculator?.let { + setPathAndTitleForStorage( + storageDevice.storagePathAndTitle(context, index, sharedPreferenceUtil, it) + ) + setFreeSpace(storageDevice.getFreeSpace(context, it)) + setUsedSpace(storageDevice.getUsedSpace(context, it)) + setProgress(storageDevice.usedPercentage(it)) + } } } } diff --git a/core/src/main/java/eu/mhutti1/utils/storage/StorageSelectDialog.kt b/core/src/main/java/eu/mhutti1/utils/storage/StorageSelectDialog.kt index c37989c768..c4466505b8 100644 --- a/core/src/main/java/eu/mhutti1/utils/storage/StorageSelectDialog.kt +++ b/core/src/main/java/eu/mhutti1/utils/storage/StorageSelectDialog.kt @@ -25,6 +25,7 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentManager +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import eu.mhutti1.utils.storage.adapter.StorageAdapter @@ -56,7 +57,8 @@ class StorageSelectDialog : DialogFragment() { StorageDelegate( storageCalculator, sharedPreferenceUtil, - shouldShowCheckboxSelected + lifecycleScope, + shouldShowCheckboxSelected, ) { onSelectAction?.invoke(it) dismiss() diff --git a/core/src/main/java/eu/mhutti1/utils/storage/adapter/StorageDelegate.kt b/core/src/main/java/eu/mhutti1/utils/storage/adapter/StorageDelegate.kt index c809f84764..c842314bfa 100644 --- a/core/src/main/java/eu/mhutti1/utils/storage/adapter/StorageDelegate.kt +++ b/core/src/main/java/eu/mhutti1/utils/storage/adapter/StorageDelegate.kt @@ -21,6 +21,7 @@ package eu.mhutti1.utils.storage.adapter import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView.ViewHolder import eu.mhutti1.utils.storage.StorageDevice +import kotlinx.coroutines.CoroutineScope import org.kiwix.kiwixmobile.core.base.adapter.AdapterDelegate import org.kiwix.kiwixmobile.core.databinding.ItemStoragePreferenceBinding import org.kiwix.kiwixmobile.core.extensions.ViewGroupExtensions.viewBinding @@ -30,6 +31,7 @@ import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil class StorageDelegate( private val storageCalculator: StorageCalculator, private val sharedPreferenceUtil: SharedPreferenceUtil, + private val lifecycleScope: CoroutineScope, private val shouldShowCheckboxSelected: Boolean, private val onClickAction: (StorageDevice) -> Unit ) : AdapterDelegate { @@ -37,6 +39,7 @@ class StorageDelegate( return StorageViewHolder( parent.viewBinding(ItemStoragePreferenceBinding::inflate, false), storageCalculator, + lifecycleScope, sharedPreferenceUtil, shouldShowCheckboxSelected, onClickAction diff --git a/core/src/main/java/eu/mhutti1/utils/storage/adapter/StorageViewHolder.kt b/core/src/main/java/eu/mhutti1/utils/storage/adapter/StorageViewHolder.kt index 05f6492d84..3408a8cc98 100644 --- a/core/src/main/java/eu/mhutti1/utils/storage/adapter/StorageViewHolder.kt +++ b/core/src/main/java/eu/mhutti1/utils/storage/adapter/StorageViewHolder.kt @@ -24,6 +24,8 @@ import android.text.SpannableStringBuilder import android.text.style.AbsoluteSizeSpan import android.view.View.VISIBLE import eu.mhutti1.utils.storage.StorageDevice +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.base.adapter.BaseViewHolder import org.kiwix.kiwixmobile.core.databinding.ItemStoragePreferenceBinding @@ -40,46 +42,50 @@ const val FREE_SPACE_TEXTVIEW_SIZE = 12F const val STORAGE_TITLE_TEXTVIEW_SIZE = 15 @SuppressLint("SetTextI18n") +@Suppress("LongParameterList") internal class StorageViewHolder( private val itemStoragePreferenceBinding: ItemStoragePreferenceBinding, private val storageCalculator: StorageCalculator, + private val lifecycleScope: CoroutineScope, private val sharedPreferenceUtil: SharedPreferenceUtil, private val shouldShowCheckboxSelected: Boolean, private val onClickAction: (StorageDevice) -> Unit ) : BaseViewHolder(itemStoragePreferenceBinding.root) { override fun bind(item: StorageDevice) { - with(itemStoragePreferenceBinding) { - storagePathAndTitle.text = - resizeStoragePathAndTitle( - item.storagePathAndTitle( - root.context, - adapterPosition, - sharedPreferenceUtil, - storageCalculator + lifecycleScope.launch { + with(itemStoragePreferenceBinding) { + storagePathAndTitle.text = + resizeStoragePathAndTitle( + item.storagePathAndTitle( + root.context, + adapterPosition, + sharedPreferenceUtil, + storageCalculator + ) ) - ) - radioButton.isChecked = shouldShowCheckboxSelected && - adapterPosition == sharedPreferenceUtil.storagePosition - freeSpace.apply { - text = item.getFreeSpace(root.context, storageCalculator) - textSize = FREE_SPACE_TEXTVIEW_SIZE - } - usedSpace.apply { - text = item.getUsedSpace(root.context, storageCalculator) - textSize = FREE_SPACE_TEXTVIEW_SIZE - } - storageProgressBar.progress = item.usedPercentage(storageCalculator) - clickOverlay.apply { - visibility = VISIBLE - setToolTipWithContentDescription( - root.context.getString( - R.string.storage_selection_dialog_accessibility_description + radioButton.isChecked = shouldShowCheckboxSelected && + adapterPosition == sharedPreferenceUtil.storagePosition + freeSpace.apply { + text = item.getFreeSpace(root.context, storageCalculator) + textSize = FREE_SPACE_TEXTVIEW_SIZE + } + usedSpace.apply { + text = item.getUsedSpace(root.context, storageCalculator) + textSize = FREE_SPACE_TEXTVIEW_SIZE + } + storageProgressBar.progress = item.usedPercentage(storageCalculator) + clickOverlay.apply { + visibility = VISIBLE + setToolTipWithContentDescription( + root.context.getString( + R.string.storage_selection_dialog_accessibility_description + ) ) - ) - setOnClickListener { - onClickAction.invoke(item) + setOnClickListener { + onClickAction.invoke(item) + } } } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/FileExtensions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/FileExtensions.kt index 95c733ded9..9ba4e9cfe0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/FileExtensions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/FileExtensions.kt @@ -35,11 +35,7 @@ fun File.freeSpace(): Long = runBlocking { } } -fun File.totalSpace(): Long = runBlocking { - withContext(Dispatchers.IO) { - totalSpace - } -} +suspend fun File.totalSpace(): Long = withContext(Dispatchers.IO) { totalSpace } suspend fun File.canReadFile(): Boolean = withContext(Dispatchers.IO) { canRead() } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/StorageDeviceExtensions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/StorageDeviceExtensions.kt index edc62ba8f1..383fa4635d 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/StorageDeviceExtensions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/StorageDeviceExtensions.kt @@ -29,20 +29,23 @@ fun StorageDevice.getFreeSpace(context: Context, storageCalculator: StorageCalcu return context.getString(R.string.pref_free_storage, freeSpace) } -fun StorageDevice.getUsedSpace(context: Context, storageCalculator: StorageCalculator): String { +suspend fun StorageDevice.getUsedSpace( + context: Context, + storageCalculator: StorageCalculator +): String { val usedSpace = storageCalculator.calculateUsedSpace(file) return context.getString(R.string.pref_storage_used, usedSpace) } @Suppress("MagicNumber") -fun StorageDevice.usedPercentage(storageCalculator: StorageCalculator): Int { +suspend fun StorageDevice.usedPercentage(storageCalculator: StorageCalculator): Int { val totalSpace = storageCalculator.totalBytes(file) val availableSpace = storageCalculator.availableBytes(file) val usedSpace = totalSpace - availableSpace return (usedSpace.toDouble() / totalSpace * 100).toInt() } -fun StorageDevice.storagePathAndTitle( +suspend fun StorageDevice.storagePathAndTitle( context: Context, index: Int, sharedPreferenceUtil: SharedPreferenceUtil, diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.kt index 65638c765f..cf4f366e07 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.kt @@ -34,6 +34,7 @@ import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope import androidx.preference.EditTextPreference import androidx.preference.ListPreference import androidx.preference.Preference @@ -97,20 +98,22 @@ abstract class CorePrefsFragment : @Inject internal var libkiwixBookmarks: LibkiwixBookmarks? = null override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - coreComponent - .activityComponentBuilder() - .activity(requireActivity()) - .build() - .inject(this) - addPreferencesFromResource(R.xml.preferences) - setStorage() - setUpSettings() - setupZoom() - sharedPreferenceUtil?.let { - LanguageUtils(requireActivity()).changeFont( - requireActivity(), - it - ) + lifecycleScope.launch { + coreComponent + .activityComponentBuilder() + .activity(requireActivity()) + .build() + .inject(this@CorePrefsFragment) + addPreferencesFromResource(R.xml.preferences) + setStorage() + setUpSettings() + setupZoom() + sharedPreferenceUtil?.let { + LanguageUtils(requireActivity()).changeFont( + requireActivity(), + it + ) + } } } @@ -129,7 +132,7 @@ abstract class CorePrefsFragment : textZoom?.summary = getString(R.string.percentage, sharedPreferenceUtil?.textZoom) } - protected abstract fun setStorage() + protected abstract suspend fun setStorage() override fun onResume() { super.onResume() preferenceScreen.sharedPreferences @@ -448,18 +451,19 @@ abstract class CorePrefsFragment : @Suppress("NestedBlockDepth") fun onStorageDeviceSelected(storageDevice: StorageDevice) { - sharedPreferenceUtil?.let { sharedPreferenceUtil -> - sharedPreferenceUtil.putPrefStorage( - sharedPreferenceUtil.getPublicDirectoryPath(storageDevice.name) - ) - sharedPreferenceUtil.putStoragePosition( - if (storageDevice.isInternal) INTERNAL_SELECT_POSITION - else EXTERNAL_SELECT_POSITION - ) - setShowStorageOption() - setStorage() + lifecycleScope.launch { + sharedPreferenceUtil?.let { sharedPreferenceUtil -> + sharedPreferenceUtil.putPrefStorage( + sharedPreferenceUtil.getPublicDirectoryPath(storageDevice.name) + ) + sharedPreferenceUtil.putStoragePosition( + if (storageDevice.isInternal) INTERNAL_SELECT_POSITION + else EXTERNAL_SELECT_POSITION + ) + setShowStorageOption() + setStorage() + } } - return } private fun setShowStorageOption() { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/StorageCalculator.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/StorageCalculator.kt index 8fffecdbef..2e366a5f61 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/StorageCalculator.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/StorageCalculator.kt @@ -33,15 +33,15 @@ class StorageCalculator @Inject constructor( fun calculateAvailableSpace(file: File = File(sharedPreferenceUtil.prefStorage)): String = Bytes(availableBytes(file)).humanReadable - fun calculateTotalSpace(file: File = File(sharedPreferenceUtil.prefStorage)): String = + suspend fun calculateTotalSpace(file: File = File(sharedPreferenceUtil.prefStorage)): String = Bytes(totalBytes(file)).humanReadable - fun calculateUsedSpace(file: File): String = + suspend 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 - fun totalBytes(file: File) = if (file.isFileExist()) file.totalSpace() else 0L + suspend fun totalBytes(file: File) = if (file.isFileExist()) file.totalSpace() else 0L } diff --git a/core/src/test/java/org/kiwix/kiwixmobile/core/settings/StorageCalculatorTest.kt b/core/src/test/java/org/kiwix/kiwixmobile/core/settings/StorageCalculatorTest.kt index dadced942f..eddc7840c7 100644 --- a/core/src/test/java/org/kiwix/kiwixmobile/core/settings/StorageCalculatorTest.kt +++ b/core/src/test/java/org/kiwix/kiwixmobile/core/settings/StorageCalculatorTest.kt @@ -20,6 +20,7 @@ package org.kiwix.kiwixmobile.core.settings import io.mockk.every import io.mockk.mockk +import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import java.io.File @@ -37,14 +38,14 @@ internal class StorageCalculatorTest { } @Test - fun `calculate total space of existing file`() { + fun `calculate total space of existing file`() = runTest { every { file.totalSpace } returns 1 every { file.exists() } returns true assertThat(storageCalculator.calculateTotalSpace(file)).isEqualTo("1 Bytes") } @Test - fun `calculate total space of non existing file`() { + fun `calculate total space of non existing file`() = runTest { every { file.exists() } returns false assertThat(storageCalculator.calculateTotalSpace(file)).isEqualTo("0 Bytes") } diff --git a/custom/src/main/java/org/kiwix/kiwixmobile/custom/settings/CustomPrefsFragment.kt b/custom/src/main/java/org/kiwix/kiwixmobile/custom/settings/CustomPrefsFragment.kt index 7ab9236f25..9694ee93cf 100644 --- a/custom/src/main/java/org/kiwix/kiwixmobile/custom/settings/CustomPrefsFragment.kt +++ b/custom/src/main/java/org/kiwix/kiwixmobile/custom/settings/CustomPrefsFragment.kt @@ -50,7 +50,7 @@ class CustomPrefsFragment : CorePrefsFragment() { sharedPreferenceUtil?.putPrefExternalLinkPopup(false) } - override fun setStorage() { + override suspend fun setStorage() { findPreference("pref_storage")?.let(preferenceScreen::removePreference) } }