mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
Merge pull request #4164 from kiwix/Fixes#4163
Fixed: Application crash caused by "Input dispatching timed out" while retrieving storageDeviceList information in the online library.
This commit is contained in:
commit
1e5bc58f15
@ -40,6 +40,7 @@ import androidx.navigation.fragment.NavHostFragment
|
|||||||
import androidx.navigation.ui.NavigationUI
|
import androidx.navigation.ui.NavigationUI
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.google.android.material.navigation.NavigationView
|
import com.google.android.material.navigation.NavigationView
|
||||||
|
import eu.mhutti1.utils.storage.StorageDevice
|
||||||
import eu.mhutti1.utils.storage.StorageDeviceUtils
|
import eu.mhutti1.utils.storage.StorageDeviceUtils
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.kiwix.kiwixmobile.BuildConfig
|
import org.kiwix.kiwixmobile.BuildConfig
|
||||||
@ -115,6 +116,7 @@ class KiwixMainActivity : CoreMainActivity() {
|
|||||||
NavController.OnDestinationChangedListener { _, _, _ ->
|
NavController.OnDestinationChangedListener { _, _, _ ->
|
||||||
actionMode?.finish()
|
actionMode?.finish()
|
||||||
}
|
}
|
||||||
|
private val storageDeviceList = arrayListOf<StorageDevice>()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
cachedComponent.inject(this)
|
cachedComponent.inject(this)
|
||||||
@ -142,7 +144,7 @@ class KiwixMainActivity : CoreMainActivity() {
|
|||||||
|
|
||||||
private suspend fun migrateInternalToPublicAppDirectory() {
|
private suspend fun migrateInternalToPublicAppDirectory() {
|
||||||
if (!sharedPreferenceUtil.prefIsAppDirectoryMigrated) {
|
if (!sharedPreferenceUtil.prefIsAppDirectoryMigrated) {
|
||||||
val storagePath = StorageDeviceUtils.getWritableStorage(this)
|
val storagePath = getStorageDeviceList()
|
||||||
.getOrNull(sharedPreferenceUtil.storagePosition)
|
.getOrNull(sharedPreferenceUtil.storagePosition)
|
||||||
?.name
|
?.name
|
||||||
storagePath?.let {
|
storagePath?.let {
|
||||||
@ -152,6 +154,23 @@ class KiwixMainActivity : CoreMainActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the storage device list once in the main activity and reuses it across all fragments.
|
||||||
|
* This is necessary because retrieving the storage device list, especially on devices with large SD cards,
|
||||||
|
* is a resource-intensive operation. Performing this operation repeatedly in fragments can negatively
|
||||||
|
* affect the user experience, as it takes time and can block the UI.
|
||||||
|
*
|
||||||
|
* If a fragment is destroyed and we need to retrieve the device list again, performing the operation
|
||||||
|
* repeatedly leads to inefficiency. To optimize this, we fetch the storage device list once and reuse
|
||||||
|
* it in all fragments, thereby reducing redundant processing and improving performance.
|
||||||
|
*/
|
||||||
|
suspend fun getStorageDeviceList(): List<StorageDevice> {
|
||||||
|
if (storageDeviceList.isEmpty()) {
|
||||||
|
storageDeviceList.addAll(StorageDeviceUtils.getWritableStorage(this))
|
||||||
|
}
|
||||||
|
return storageDeviceList
|
||||||
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
super.onConfigurationChanged(newConfig)
|
||||||
if (::activityKiwixMainBinding.isInitialized) {
|
if (::activityKiwixMainBinding.isInitialized) {
|
||||||
|
@ -33,7 +33,6 @@ import androidx.documentfile.provider.DocumentFile
|
|||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import eu.mhutti1.utils.storage.STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
|
import eu.mhutti1.utils.storage.STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
|
||||||
import eu.mhutti1.utils.storage.StorageDevice
|
import eu.mhutti1.utils.storage.StorageDevice
|
||||||
import eu.mhutti1.utils.storage.StorageDeviceUtils
|
|
||||||
import eu.mhutti1.utils.storage.StorageSelectDialog
|
import eu.mhutti1.utils.storage.StorageSelectDialog
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
@ -53,6 +52,7 @@ import org.kiwix.kiwixmobile.core.utils.INTERNAL_SELECT_POSITION
|
|||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||||
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
|
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
|
||||||
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
|
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
|
||||||
|
import org.kiwix.kiwixmobile.main.KiwixMainActivity
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.Companion.FOUR_GIGABYTES_IN_KILOBYTES
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.Companion.FOUR_GIGABYTES_IN_KILOBYTES
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CannotWrite4GbFile
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CannotWrite4GbFile
|
||||||
@ -83,9 +83,6 @@ class CopyMoveFileHandler @Inject constructor(
|
|||||||
var shouldValidateZimFile: Boolean = false
|
var shouldValidateZimFile: Boolean = false
|
||||||
private var fileSystemDisposable: Disposable? = null
|
private var fileSystemDisposable: Disposable? = null
|
||||||
private lateinit var fragmentManager: FragmentManager
|
private lateinit var fragmentManager: FragmentManager
|
||||||
val storageDeviceList by lazy {
|
|
||||||
StorageDeviceUtils.getWritableStorage(activity)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val copyMoveTitle: String by lazy {
|
private val copyMoveTitle: String by lazy {
|
||||||
if (isMoveOperation) {
|
if (isMoveOperation) {
|
||||||
@ -111,18 +108,23 @@ class CopyMoveFileHandler @Inject constructor(
|
|||||||
this.shouldValidateZimFile = shouldValidateZimFile
|
this.shouldValidateZimFile = shouldValidateZimFile
|
||||||
this.fragmentManager = fragmentManager
|
this.fragmentManager = fragmentManager
|
||||||
setSelectedFileAndUri(uri, documentFile)
|
setSelectedFileAndUri(uri, documentFile)
|
||||||
if (sharedPreferenceUtil.shouldShowStorageSelectionDialog && storageDeviceList.size > 1) {
|
if (getStorageDeviceList().isEmpty()) {
|
||||||
|
showPreparingCopyMoveDialog()
|
||||||
|
}
|
||||||
|
if (sharedPreferenceUtil.shouldShowStorageSelectionDialog && getStorageDeviceList().size > 1) {
|
||||||
// Show dialog to select storage if more than one storage device is available, and user
|
// Show dialog to select storage if more than one storage device is available, and user
|
||||||
// have not configured the storage yet.
|
// have not configured the storage yet.
|
||||||
|
hidePreparingCopyMoveDialog()
|
||||||
showCopyMoveDialog(true)
|
showCopyMoveDialog(true)
|
||||||
} else {
|
} else {
|
||||||
if (storageDeviceList.size == 1) {
|
if (getStorageDeviceList().size == 1) {
|
||||||
// If only internal storage is currently available, set shouldShowStorageSelectionDialog
|
// If only internal storage is currently available, set shouldShowStorageSelectionDialog
|
||||||
// to true. This allows the storage configuration dialog to be shown again if the
|
// to true. This allows the storage configuration dialog to be shown again if the
|
||||||
// user removes an external storage device (like an SD card) and then reinserts it.
|
// user removes an external storage device (like an SD card) and then reinserts it.
|
||||||
// This ensures they are prompted to configure storage settings upon SD card reinsertion.
|
// This ensures they are prompted to configure storage settings upon SD card reinsertion.
|
||||||
sharedPreferenceUtil.shouldShowStorageSelectionDialog = true
|
sharedPreferenceUtil.shouldShowStorageSelectionDialog = true
|
||||||
}
|
}
|
||||||
|
hidePreparingCopyMoveDialog()
|
||||||
if (validateZimFileCanCopyOrMove()) {
|
if (validateZimFileCanCopyOrMove()) {
|
||||||
showCopyMoveDialog()
|
showCopyMoveDialog()
|
||||||
}
|
}
|
||||||
@ -142,17 +144,15 @@ class CopyMoveFileHandler @Inject constructor(
|
|||||||
lifecycleScope = coroutineScope
|
lifecycleScope = coroutineScope
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showStorageSelectDialog() = StorageSelectDialog()
|
fun showStorageSelectDialog(storageDeviceList: List<StorageDevice>) =
|
||||||
.apply {
|
StorageSelectDialog()
|
||||||
onSelectAction = ::copyMoveZIMFileInSelectedStorage
|
.apply {
|
||||||
titleSize = STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
|
onSelectAction = ::copyMoveZIMFileInSelectedStorage
|
||||||
setStorageDeviceList(storageDeviceList)
|
titleSize = STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
|
||||||
setShouldShowCheckboxSelected(false)
|
setStorageDeviceList(storageDeviceList)
|
||||||
}
|
setShouldShowCheckboxSelected(false)
|
||||||
.show(
|
}
|
||||||
fragmentManager,
|
.show(fragmentManager, activity.getString(R.string.choose_storage_to_copy_move_zim_file))
|
||||||
activity.getString(R.string.choose_storage_to_copy_move_zim_file)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun copyMoveZIMFileInSelectedStorage(storageDevice: StorageDevice) {
|
fun copyMoveZIMFileInSelectedStorage(storageDevice: StorageDevice) {
|
||||||
lifecycleScope?.launch {
|
lifecycleScope?.launch {
|
||||||
@ -259,19 +259,23 @@ class CopyMoveFileHandler @Inject constructor(
|
|||||||
|
|
||||||
fun performCopyOperation(showStorageSelectionDialog: Boolean = false) {
|
fun performCopyOperation(showStorageSelectionDialog: Boolean = false) {
|
||||||
isMoveOperation = false
|
isMoveOperation = false
|
||||||
if (showStorageSelectionDialog) {
|
lifecycleScope?.launch {
|
||||||
showStorageSelectDialog()
|
if (showStorageSelectionDialog) {
|
||||||
} else {
|
showStorageSelectDialog(getStorageDeviceList())
|
||||||
copyZimFileToPublicAppDirectory()
|
} else {
|
||||||
|
copyZimFileToPublicAppDirectory()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun performMoveOperation(showStorageSelectionDialog: Boolean = false) {
|
fun performMoveOperation(showStorageSelectionDialog: Boolean = false) {
|
||||||
isMoveOperation = true
|
isMoveOperation = true
|
||||||
if (showStorageSelectionDialog) {
|
lifecycleScope?.launch {
|
||||||
showStorageSelectDialog()
|
if (showStorageSelectionDialog) {
|
||||||
} else {
|
showStorageSelectDialog(getStorageDeviceList())
|
||||||
moveZimFileToPublicAppDirectory()
|
} else {
|
||||||
|
moveZimFileToPublicAppDirectory()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,6 +542,9 @@ class CopyMoveFileHandler @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getStorageDeviceList() =
|
||||||
|
(activity as KiwixMainActivity).getStorageDeviceList()
|
||||||
|
|
||||||
fun dispose() {
|
fun dispose() {
|
||||||
fileSystemDisposable?.dispose()
|
fileSystemDisposable?.dispose()
|
||||||
setFileCopyMoveCallback(null)
|
setFileCopyMoveCallback(null)
|
||||||
|
@ -58,7 +58,6 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import eu.mhutti1.utils.storage.Bytes
|
import eu.mhutti1.utils.storage.Bytes
|
||||||
import eu.mhutti1.utils.storage.StorageDevice
|
import eu.mhutti1.utils.storage.StorageDevice
|
||||||
import eu.mhutti1.utils.storage.StorageDeviceUtils
|
|
||||||
import eu.mhutti1.utils.storage.StorageSelectDialog
|
import eu.mhutti1.utils.storage.StorageSelectDialog
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
@ -99,6 +98,7 @@ import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDis
|
|||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
|
||||||
import org.kiwix.kiwixmobile.databinding.FragmentDestinationLibraryBinding
|
import org.kiwix.kiwixmobile.databinding.FragmentDestinationLibraryBinding
|
||||||
|
import org.kiwix.kiwixmobile.main.KiwixMainActivity
|
||||||
import org.kiwix.kiwixmobile.zimManager.MAX_PROGRESS
|
import org.kiwix.kiwixmobile.zimManager.MAX_PROGRESS
|
||||||
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel
|
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel
|
||||||
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel.FileSelectActions
|
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel.FileSelectActions
|
||||||
@ -135,9 +135,6 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
|||||||
private val zimManageViewModel by lazy {
|
private val zimManageViewModel by lazy {
|
||||||
requireActivity().viewModel<ZimManageViewModel>(viewModelFactory)
|
requireActivity().viewModel<ZimManageViewModel>(viewModelFactory)
|
||||||
}
|
}
|
||||||
private val storageDeviceList by lazy {
|
|
||||||
StorageDeviceUtils.getWritableStorage(requireActivity())
|
|
||||||
}
|
|
||||||
|
|
||||||
private var storagePermissionLauncher: ActivityResultLauncher<Array<String>>? =
|
private var storagePermissionLauncher: ActivityResultLauncher<Array<String>>? =
|
||||||
registerForActivityResult(
|
registerForActivityResult(
|
||||||
@ -665,17 +662,22 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
|||||||
message,
|
message,
|
||||||
requireActivity().findViewById(R.id.bottom_nav_view),
|
requireActivity().findViewById(R.id.bottom_nav_view),
|
||||||
string.download_change_storage,
|
string.download_change_storage,
|
||||||
::showStorageSelectDialog
|
{
|
||||||
|
lifecycleScope.launch {
|
||||||
|
showStorageSelectDialog((requireActivity() as KiwixMainActivity).getStorageDeviceList())
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showStorageSelectDialog() = StorageSelectDialog()
|
private fun showStorageSelectDialog(storageDeviceList: List<StorageDevice>) =
|
||||||
.apply {
|
StorageSelectDialog()
|
||||||
onSelectAction = ::storeDeviceInPreferences
|
.apply {
|
||||||
setStorageDeviceList(storageDeviceList)
|
onSelectAction = ::storeDeviceInPreferences
|
||||||
setShouldShowCheckboxSelected(true)
|
setStorageDeviceList(storageDeviceList)
|
||||||
}
|
setShouldShowCheckboxSelected(true)
|
||||||
.show(parentFragmentManager, getString(string.pref_storage))
|
}
|
||||||
|
.show(parentFragmentManager, getString(string.pref_storage))
|
||||||
|
|
||||||
private fun storeDeviceInPreferences(
|
private fun storeDeviceInPreferences(
|
||||||
storageDevice: StorageDevice
|
storageDevice: StorageDevice
|
||||||
|
@ -53,7 +53,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.mhutti1.utils.storage.STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
|
import eu.mhutti1.utils.storage.STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
|
||||||
import eu.mhutti1.utils.storage.StorageDevice
|
import eu.mhutti1.utils.storage.StorageDevice
|
||||||
import eu.mhutti1.utils.storage.StorageDeviceUtils
|
|
||||||
import eu.mhutti1.utils.storage.StorageSelectDialog
|
import eu.mhutti1.utils.storage.StorageSelectDialog
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.kiwix.kiwixmobile.R
|
import org.kiwix.kiwixmobile.R
|
||||||
@ -93,6 +92,7 @@ import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
|
|||||||
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.YesNoDialog.WifiOnly
|
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.YesNoDialog.WifiOnly
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.NetworkState
|
import org.kiwix.kiwixmobile.core.zim_manager.NetworkState
|
||||||
import org.kiwix.kiwixmobile.databinding.FragmentDestinationDownloadBinding
|
import org.kiwix.kiwixmobile.databinding.FragmentDestinationDownloadBinding
|
||||||
|
import org.kiwix.kiwixmobile.main.KiwixMainActivity
|
||||||
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel
|
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.AvailableSpaceCalculator
|
import org.kiwix.kiwixmobile.zimManager.libraryView.AvailableSpaceCalculator
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryAdapter
|
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryAdapter
|
||||||
@ -116,9 +116,6 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
private val zimManageViewModel by lazy {
|
private val zimManageViewModel by lazy {
|
||||||
requireActivity().viewModel<ZimManageViewModel>(viewModelFactory)
|
requireActivity().viewModel<ZimManageViewModel>(viewModelFactory)
|
||||||
}
|
}
|
||||||
private val storageDeviceList by lazy {
|
|
||||||
StorageDeviceUtils.getWritableStorage(requireActivity())
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
fun getOnlineLibraryList() = libraryAdapter.items
|
fun getOnlineLibraryList() = libraryAdapter.items
|
||||||
@ -550,8 +547,8 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
|
|
||||||
else -> if (sharedPreferenceUtil.showStorageOption) {
|
else -> if (sharedPreferenceUtil.showStorageOption) {
|
||||||
// Show the storage selection dialog for configuration if there is an SD card available.
|
// Show the storage selection dialog for configuration if there is an SD card available.
|
||||||
if (storageDeviceList.size > 1) {
|
if (getStorageDeviceList().size > 1) {
|
||||||
showStorageSelectDialog()
|
showStorageSelectDialog(getStorageDeviceList())
|
||||||
} else {
|
} else {
|
||||||
// If only internal storage is available, proceed with the ZIM file download directly.
|
// If only internal storage is available, proceed with the ZIM file download directly.
|
||||||
// Displaying a configuration dialog is unnecessary in this case.
|
// Displaying a configuration dialog is unnecessary in this case.
|
||||||
@ -575,7 +572,11 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
requireActivity().findViewById(R.id.bottom_nav_view),
|
requireActivity().findViewById(R.id.bottom_nav_view),
|
||||||
string.download_change_storage,
|
string.download_change_storage,
|
||||||
::showStorageSelectDialog
|
{
|
||||||
|
lifecycleScope.launch {
|
||||||
|
showStorageSelectDialog(getStorageDeviceList())
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -588,14 +589,15 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showStorageSelectDialog() = StorageSelectDialog()
|
private fun showStorageSelectDialog(storageDeviceList: List<StorageDevice>) =
|
||||||
.apply {
|
StorageSelectDialog()
|
||||||
onSelectAction = ::storeDeviceInPreferences
|
.apply {
|
||||||
titleSize = STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
|
onSelectAction = ::storeDeviceInPreferences
|
||||||
setStorageDeviceList(storageDeviceList)
|
titleSize = STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
|
||||||
setShouldShowCheckboxSelected(false)
|
setStorageDeviceList(storageDeviceList)
|
||||||
}
|
setShouldShowCheckboxSelected(false)
|
||||||
.show(parentFragmentManager, getString(string.choose_storage_to_download_book))
|
}
|
||||||
|
.show(parentFragmentManager, getString(string.choose_storage_to_download_book))
|
||||||
|
|
||||||
private fun clickOnBookItem() {
|
private fun clickOnBookItem() {
|
||||||
if (!requireActivity().isManageExternalStoragePermissionGranted(sharedPreferenceUtil)) {
|
if (!requireActivity().isManageExternalStoragePermissionGranted(sharedPreferenceUtil)) {
|
||||||
@ -615,4 +617,7 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getStorageDeviceList() =
|
||||||
|
(activity as KiwixMainActivity).getStorageDeviceList()
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,6 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceCategory
|
import androidx.preference.PreferenceCategory
|
||||||
import eu.mhutti1.utils.storage.StorageDevice
|
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 kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.kiwix.kiwixmobile.core.R
|
import org.kiwix.kiwixmobile.core.R
|
||||||
import org.kiwix.kiwixmobile.core.extensions.getFreeSpace
|
import org.kiwix.kiwixmobile.core.extensions.getFreeSpace
|
||||||
@ -44,11 +39,11 @@ import org.kiwix.kiwixmobile.core.settings.StorageRadioButtonPreference
|
|||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil.Companion.PREF_EXTERNAL_STORAGE
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil.Companion.PREF_EXTERNAL_STORAGE
|
||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil.Companion.PREF_INTERNAL_STORAGE
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil.Companion.PREF_INTERNAL_STORAGE
|
||||||
|
import org.kiwix.kiwixmobile.main.KiwixMainActivity
|
||||||
|
|
||||||
const val PREF_STORAGE_PROGRESSBAR = "storage_progressbar"
|
const val PREF_STORAGE_PROGRESSBAR = "storage_progressbar"
|
||||||
|
|
||||||
class KiwixPrefsFragment : CorePrefsFragment() {
|
class KiwixPrefsFragment : CorePrefsFragment() {
|
||||||
private var storageDisposable: Disposable? = null
|
|
||||||
private var storageDeviceList: List<StorageDevice> = listOf()
|
private var storageDeviceList: List<StorageDevice> = listOf()
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
@ -65,20 +60,13 @@ class KiwixPrefsFragment : CorePrefsFragment() {
|
|||||||
return@setStorage
|
return@setStorage
|
||||||
}
|
}
|
||||||
showHideProgressBarWhileFetchingStorageInfo(true)
|
showHideProgressBarWhileFetchingStorageInfo(true)
|
||||||
storageDisposable =
|
lifecycleScope.launch {
|
||||||
Flowable.fromCallable { StorageDeviceUtils.getWritableStorage(requireActivity()) }
|
storageDeviceList = (requireActivity() as KiwixMainActivity).getStorageDeviceList()
|
||||||
.subscribeOn(Schedulers.io())
|
showHideProgressBarWhileFetchingStorageInfo(false)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
showInternalStoragePreferece()
|
||||||
.subscribe(
|
showExternalPreferenceIfAvailable()
|
||||||
{ storageList ->
|
setUpStoragePreference(it)
|
||||||
storageDeviceList = storageList
|
}
|
||||||
showHideProgressBarWhileFetchingStorageInfo(false)
|
|
||||||
showInternalStoragePreferece()
|
|
||||||
showExternalPreferenceIfAvailable()
|
|
||||||
setUpStoragePreference(it)
|
|
||||||
},
|
|
||||||
Throwable::printStackTrace
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,12 +145,6 @@ class KiwixPrefsFragment : CorePrefsFragment() {
|
|||||||
preferenceCategory?.isVisible = true
|
preferenceCategory?.isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
storageDisposable?.dispose()
|
|
||||||
storageDisposable = null
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PREF_MANAGE_EXTERNAL_STORAGE_PERMISSION =
|
const val PREF_MANAGE_EXTERNAL_STORAGE_PERMISSION =
|
||||||
"pref_manage_external_storage"
|
"pref_manage_external_storage"
|
||||||
|
@ -22,6 +22,7 @@ import android.app.Activity
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import eu.mhutti1.utils.storage.StorageDevice
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.clearAllMocks
|
import io.mockk.clearAllMocks
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
@ -207,9 +208,11 @@ class CopyMoveFileHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
fun showStorageConfigureDialogAtFirstLaunch() = runBlocking {
|
fun showStorageConfigureDialogAtFirstLaunch() = runBlocking {
|
||||||
fileHandler = spyk(fileHandler)
|
fileHandler = spyk(fileHandler)
|
||||||
every { fileHandler.showStorageSelectDialog() } just Runs
|
val storageDeviceList = listOf<StorageDevice>(mockk(), mockk())
|
||||||
|
every { fileHandler.showStorageSelectDialog(storageDeviceList) } just Runs
|
||||||
|
|
||||||
every { sharedPreferenceUtil.shouldShowStorageSelectionDialog } returns true
|
every { sharedPreferenceUtil.shouldShowStorageSelectionDialog } returns true
|
||||||
every { fileHandler.storageDeviceList } returns listOf(mockk(), mockk())
|
coEvery { fileHandler.getStorageDeviceList() } returns storageDeviceList
|
||||||
val positiveButtonClickSlot = slot<() -> Unit>()
|
val positiveButtonClickSlot = slot<() -> Unit>()
|
||||||
every {
|
every {
|
||||||
alertDialogShower.show(
|
alertDialogShower.show(
|
||||||
@ -221,14 +224,15 @@ class CopyMoveFileHandlerTest {
|
|||||||
fileHandler.showMoveFileToPublicDirectoryDialog(fragmentManager = fragmentManager)
|
fileHandler.showMoveFileToPublicDirectoryDialog(fragmentManager = fragmentManager)
|
||||||
coEvery { fileHandler.validateZimFileCanCopyOrMove() } returns true
|
coEvery { fileHandler.validateZimFileCanCopyOrMove() } returns true
|
||||||
positiveButtonClickSlot.captured.invoke()
|
positiveButtonClickSlot.captured.invoke()
|
||||||
verify { fileHandler.showStorageSelectDialog() }
|
testDispatcher.scheduler.advanceUntilIdle()
|
||||||
|
coVerify { fileHandler.showStorageSelectDialog(storageDeviceList) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun shouldNotShowStorageConfigureDialogWhenThereIsOnlyInternalAvailable() = runBlocking {
|
fun shouldNotShowStorageConfigureDialogWhenThereIsOnlyInternalAvailable() = runBlocking {
|
||||||
fileHandler = spyk(fileHandler)
|
fileHandler = spyk(fileHandler)
|
||||||
every { sharedPreferenceUtil.shouldShowStorageSelectionDialog } returns true
|
every { sharedPreferenceUtil.shouldShowStorageSelectionDialog } returns true
|
||||||
every { fileHandler.storageDeviceList } returns listOf(mockk())
|
coEvery { fileHandler.getStorageDeviceList() } returns listOf(mockk())
|
||||||
val positiveButtonClickSlot = slot<() -> Unit>()
|
val positiveButtonClickSlot = slot<() -> Unit>()
|
||||||
every {
|
every {
|
||||||
alertDialogShower.show(
|
alertDialogShower.show(
|
||||||
@ -240,14 +244,14 @@ class CopyMoveFileHandlerTest {
|
|||||||
coEvery { fileHandler.validateZimFileCanCopyOrMove() } returns true
|
coEvery { fileHandler.validateZimFileCanCopyOrMove() } returns true
|
||||||
fileHandler.showMoveFileToPublicDirectoryDialog(fragmentManager = fragmentManager)
|
fileHandler.showMoveFileToPublicDirectoryDialog(fragmentManager = fragmentManager)
|
||||||
positiveButtonClickSlot.captured.invoke()
|
positiveButtonClickSlot.captured.invoke()
|
||||||
verify(exactly = 0) { fileHandler.showStorageSelectDialog() }
|
verify(exactly = 0) { fileHandler.showStorageSelectDialog(listOf(mockk())) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showDirectlyCopyMoveDialogAfterFirstLaunch() = runBlocking {
|
fun showDirectlyCopyMoveDialogAfterFirstLaunch() = runBlocking {
|
||||||
fileHandler = spyk(fileHandler)
|
fileHandler = spyk(fileHandler)
|
||||||
every { sharedPreferenceUtil.shouldShowStorageSelectionDialog } returns false
|
every { sharedPreferenceUtil.shouldShowStorageSelectionDialog } returns false
|
||||||
every { fileHandler.storageDeviceList } returns listOf(mockk(), mockk())
|
coEvery { fileHandler.getStorageDeviceList() } returns listOf(mockk(), mockk())
|
||||||
coEvery { fileHandler.validateZimFileCanCopyOrMove() } returns true
|
coEvery { fileHandler.validateZimFileCanCopyOrMove() } returns true
|
||||||
prepareFileSystemAndFileForMockk()
|
prepareFileSystemAndFileForMockk()
|
||||||
every { alertDialogShower.show(any(), any(), any()) } just Runs
|
every { alertDialogShower.show(any(), any(), any()) } just Runs
|
||||||
@ -267,7 +271,7 @@ class CopyMoveFileHandlerTest {
|
|||||||
val positiveButtonClickSlot = slot<() -> Unit>()
|
val positiveButtonClickSlot = slot<() -> Unit>()
|
||||||
val negativeButtonClickSlot = slot<() -> Unit>()
|
val negativeButtonClickSlot = slot<() -> Unit>()
|
||||||
fileHandler = spyk(fileHandler)
|
fileHandler = spyk(fileHandler)
|
||||||
every { fileHandler.storageDeviceList } returns listOf(mockk(), mockk())
|
coEvery { fileHandler.getStorageDeviceList() } returns listOf(mockk(), mockk())
|
||||||
every { sharedPreferenceUtil.shouldShowStorageSelectionDialog } returns false
|
every { sharedPreferenceUtil.shouldShowStorageSelectionDialog } returns false
|
||||||
every {
|
every {
|
||||||
alertDialogShower.show(
|
alertDialogShower.show(
|
||||||
|
@ -21,6 +21,8 @@ package eu.mhutti1.utils.storage
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileFilter
|
import java.io.FileFilter
|
||||||
@ -28,8 +30,9 @@ import java.io.RandomAccessFile
|
|||||||
|
|
||||||
object StorageDeviceUtils {
|
object StorageDeviceUtils {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getWritableStorage(context: Context) =
|
suspend fun getWritableStorage(context: Context) = withContext(Dispatchers.IO) {
|
||||||
validate(externalMediaFilesDirsDevices(context), true)
|
validate(externalMediaFilesDirsDevices(context), true)
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getReadableStorage(context: Context): List<StorageDevice> {
|
fun getReadableStorage(context: Context): List<StorageDevice> {
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:indeterminate="false"
|
android:indeterminate="false"
|
||||||
android:max="100"
|
android:max="100"
|
||||||
android:progress="50"
|
android:progress="0"
|
||||||
android:progressDrawable="@drawable/progress_bar_state"
|
android:progressDrawable="@drawable/progress_bar_state"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/radioButton"
|
app:layout_constraintStart_toEndOf="@id/radioButton"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user