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

Move free space to io thread #4103

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ androidComponents {
}

dependencies {
implementation(Libs.kotlinx_coroutines_rx3)
androidTestImplementation(Libs.leakcanary_android_instrumentation)
testImplementation(Libs.kotlinx_coroutines_test)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class CopyMoveFileHandlerTest : BaseActivityTest() {
}

private fun showMoveFileToPublicDirectoryDialog() {
UiThreadStatement.runOnUiThread {
kiwixMainActivity.lifecycleScope.launch {
val navHostFragment: NavHostFragment =
kiwixMainActivity.supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class CopyMoveFileHandler @Inject constructor(
}
}

fun showMoveFileToPublicDirectoryDialog(
suspend fun showMoveFileToPublicDirectoryDialog(
uri: Uri? = null,
documentFile: DocumentFile? = null,
shouldValidateZimFile: Boolean = false,
Expand Down Expand Up @@ -154,16 +154,18 @@ class CopyMoveFileHandler @Inject constructor(
)

fun copyMoveZIMFileInSelectedStorage(storageDevice: StorageDevice) {
sharedPreferenceUtil.apply {
shouldShowStorageSelectionDialog = false
putPrefStorage(sharedPreferenceUtil.getPublicDirectoryPath(storageDevice.name))
putStoragePosition(
if (storageDevice.isInternal) INTERNAL_SELECT_POSITION
else EXTERNAL_SELECT_POSITION
)
}
if (validateZimFileCanCopyOrMove()) {
performCopyMoveOperation()
lifecycleScope?.launch {
sharedPreferenceUtil.apply {
shouldShowStorageSelectionDialog = false
putPrefStorage(sharedPreferenceUtil.getPublicDirectoryPath(storageDevice.name))
putStoragePosition(
if (storageDevice.isInternal) INTERNAL_SELECT_POSITION
else EXTERNAL_SELECT_POSITION
)
}
if (validateZimFileCanCopyOrMove()) {
performCopyMoveOperation()
}
}
}

Expand All @@ -181,7 +183,7 @@ class CopyMoveFileHandler @Inject constructor(
private fun hasNotSufficientStorageSpace(availableSpace: Long): Boolean =
availableSpace < (selectedFile?.length() ?: 0L)

fun validateZimFileCanCopyOrMove(file: File = File(sharedPreferenceUtil.prefStorage)): Boolean {
suspend fun validateZimFileCanCopyOrMove(file: File = File(sharedPreferenceUtil.prefStorage)): Boolean {
hidePreparingCopyMoveDialog() // hide the dialog if already showing
val availableSpace = storageCalculator.availableBytes(file)
if (hasNotSufficientStorageSpace(availableSpace)) {
Expand Down Expand Up @@ -226,19 +228,23 @@ class CopyMoveFileHandler @Inject constructor(
fileSystemDisposable = fat32Checker.fileSystemStates
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
hidePreparingCopyMoveDialog()
if (validateZimFileCanCopyOrMove()) {
performCopyMoveOperation()
lifecycleScope?.launch {
hidePreparingCopyMoveDialog()
if (validateZimFileCanCopyOrMove()) {
performCopyMoveOperation()
}
}
}
}

fun performCopyMoveOperationIfSufficientSpaceAvailable() {
val availableSpace = storageCalculator.availableBytes(File(sharedPreferenceUtil.prefStorage))
if (hasNotSufficientStorageSpace(availableSpace)) {
fileCopyMoveCallback?.insufficientSpaceInStorage(availableSpace)
} else {
performCopyMoveOperation()
lifecycleScope?.launch {
val availableSpace = storageCalculator.availableBytes(File(sharedPreferenceUtil.prefStorage))
if (hasNotSufficientStorageSpace(availableSpace)) {
fileCopyMoveCallback?.insufficientSpaceInStorage(availableSpace)
} else {
performCopyMoveOperation()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,30 +412,32 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
}

fun handleSelectedFileUri(uri: Uri) {
if (sharedPreferenceUtil.isPlayStoreBuildWithAndroid11OrAbove()) {
val documentFile = when (uri.scheme) {
"file" -> DocumentFile.fromFile(File("$uri"))
else -> {
DocumentFile.fromSingleUri(requireActivity(), uri)
lifecycleScope.launch {
if (sharedPreferenceUtil.isPlayStoreBuildWithAndroid11OrAbove()) {
val documentFile = when (uri.scheme) {
"file" -> DocumentFile.fromFile(File("$uri"))
else -> {
DocumentFile.fromSingleUri(requireActivity(), uri)
}
}
// If the file is not valid, it shows an error message and stops further processing.
// If the file name is not found, then let them to copy the file
// and we will handle this later.
val fileName = documentFile?.name
if (fileName != null && !FileUtils.isValidZimFile(fileName)) {
activity.toast(string.error_file_invalid)
return@launch
}
copyMoveFileHandler?.showMoveFileToPublicDirectoryDialog(
uri,
documentFile,
// pass if fileName is null then we will validate it after copying/moving
fileName == null,
parentFragmentManager
)
} else {
getZimFileFromUri(uri)?.let(::navigateToReaderFragment)
}
// If the file is not valid, it shows an error message and stops further processing.
// If the file name is not found, then let them to copy the file
// and we will handle this later.
val fileName = documentFile?.name
if (fileName != null && !FileUtils.isValidZimFile(fileName)) {
activity.toast(string.error_file_invalid)
return
}
copyMoveFileHandler?.showMoveFileToPublicDirectoryDialog(
uri,
documentFile,
// pass if fileName is null then we will validate it after copying/moving
fileName == null,
parentFragmentManager
)
} else {
getZimFileFromUri(uri)?.let(::navigateToReaderFragment)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import eu.mhutti1.utils.storage.STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
import eu.mhutti1.utils.storage.StorageDevice
import eu.mhutti1.utils.storage.StorageDeviceUtils
import eu.mhutti1.utils.storage.StorageSelectDialog
import kotlinx.coroutines.launch
import org.kiwix.kiwixmobile.R
import org.kiwix.kiwixmobile.cachedComponent
import org.kiwix.kiwixmobile.core.R.string
Expand Down Expand Up @@ -122,7 +124,12 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {

private val libraryAdapter: LibraryAdapter by lazy {
LibraryAdapter(
LibraryDelegate.BookDelegate(bookUtils, ::onBookItemClick, availableSpaceCalculator),
LibraryDelegate.BookDelegate(
bookUtils,
::onBookItemClick,
availableSpaceCalculator,
lifecycleScope
),
LibraryDelegate.DownloadDelegate(
{
if (it.currentDownloadState == Status.FAILED) {
Expand Down Expand Up @@ -321,7 +328,6 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {

override fun onDestroyView() {
super.onDestroyView()
availableSpaceCalculator.dispose()
fragmentDestinationDownloadBinding?.libraryList?.adapter = null
fragmentDestinationDownloadBinding = null
}
Expand Down Expand Up @@ -516,58 +522,60 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {

@Suppress("NestedBlockDepth")
private fun onBookItemClick(item: LibraryListItem.BookItem) {
if (checkExternalStorageWritePermission()) {
downloadBookItem = item
if (requireActivity().hasNotificationPermission(sharedPreferenceUtil)) {
when {
isNotConnected -> {
noInternetSnackbar()
return
}
lifecycleScope.launch {
if (checkExternalStorageWritePermission()) {
downloadBookItem = item
if (requireActivity().hasNotificationPermission(sharedPreferenceUtil)) {
when {
isNotConnected -> {
noInternetSnackbar()
return@launch
}

noWifiWithWifiOnlyPreferenceSet -> {
dialogShower.show(WifiOnly, {
sharedPreferenceUtil.putPrefWifiOnly(false)
clickOnBookItem()
})
return
}
noWifiWithWifiOnlyPreferenceSet -> {
dialogShower.show(WifiOnly, {
sharedPreferenceUtil.putPrefWifiOnly(false)
clickOnBookItem()
})
return@launch
}

else -> if (sharedPreferenceUtil.showStorageOption) {
// Show the storage selection dialog for configuration if there is an SD card available.
if (storageDeviceList.size > 1) {
showStorageSelectDialog()
else -> if (sharedPreferenceUtil.showStorageOption) {
// Show the storage selection dialog for configuration if there is an SD card available.
if (storageDeviceList.size > 1) {
showStorageSelectDialog()
} else {
// If only internal storage is available, proceed with the ZIM file download directly.
// Displaying a configuration dialog is unnecessary in this case.
sharedPreferenceUtil.showStorageOption = false
onBookItemClick(item)
}
} else if (!requireActivity().isManageExternalStoragePermissionGranted(
sharedPreferenceUtil
)
) {
showManageExternalStoragePermissionDialog()
} else {
// If only internal storage is available, proceed with the ZIM file download directly.
// Displaying a configuration dialog is unnecessary in this case.
sharedPreferenceUtil.showStorageOption = false
onBookItemClick(item)
}
} else if (!requireActivity().isManageExternalStoragePermissionGranted(
sharedPreferenceUtil
)
) {
showManageExternalStoragePermissionDialog()
} else {
availableSpaceCalculator.hasAvailableSpaceFor(
item,
{ downloadFile() },
{
fragmentDestinationDownloadBinding?.libraryList?.snack(
"""
availableSpaceCalculator.hasAvailableSpaceFor(
item,
{ downloadFile() },
{
fragmentDestinationDownloadBinding?.libraryList?.snack(
"""
${getString(string.download_no_space)}
${getString(string.space_available)} $it
""".trimIndent(),
requireActivity().findViewById(R.id.bottom_nav_view),
string.download_change_storage,
::showStorageSelectDialog
)
}
)
""".trimIndent(),
requireActivity().findViewById(R.id.bottom_nav_view),
string.download_change_storage,
::showStorageSelectDialog
)
}
)
}
}
} else {
requestNotificationPermission()
}
} else {
requestNotificationPermission()
}
}
}
Expand Down
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 Down Expand Up @@ -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
Loading
Loading