Skip to content

Commit

Permalink
Merge pull request #4061 from CalebKL/caleb/task/migrate-total-space-…
Browse files Browse the repository at this point in the history
…to-io-thread

Migrate totalSpace to IO Thread
  • Loading branch information
kelson42 authored Dec 8, 2024
2 parents 154389f + 63e3513 commit 9c8826e
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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<StorageRadioButtonPreference>(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<StorageRadioButtonPreference>(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))
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -56,7 +57,8 @@ class StorageSelectDialog : DialogFragment() {
StorageDelegate(
storageCalculator,
sharedPreferenceUtil,
shouldShowCheckboxSelected
lifecycleScope,
shouldShowCheckboxSelected,
) {
onSelectAction?.invoke(it)
dismiss()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -30,13 +31,15 @@ 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<StorageDevice> {
override fun createViewHolder(parent: ViewGroup): ViewHolder {
return StorageViewHolder(
parent.viewBinding(ItemStoragePreferenceBinding::inflate, false),
storageCalculator,
lifecycleScope,
sharedPreferenceUtil,
shouldShowCheckboxSelected,
onClickAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<StorageDevice>(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)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)
}
}
}

Expand All @@ -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
Expand Down Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class CustomPrefsFragment : CorePrefsFragment() {
sharedPreferenceUtil?.putPrefExternalLinkPopup(false)
}

override fun setStorage() {
override suspend fun setStorage() {
findPreference<Preference>("pref_storage")?.let(preferenceScreen::removePreference)
}
}

0 comments on commit 9c8826e

Please sign in to comment.