diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3ce7bbb88..e59ec060b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -106,6 +106,7 @@ androidComponents { } dependencies { + implementation(Libs.kotlinx_coroutines_rx3) androidTestImplementation(Libs.leakcanary_android_instrumentation) testImplementation(Libs.kotlinx_coroutines_test) } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt index fd990f04c..9ba5df0a4 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt @@ -208,7 +208,7 @@ class CopyMoveFileHandler @Inject constructor( } } - fun handleDetectingFileSystemState() { + suspend fun handleDetectingFileSystemState() { if (isBookLessThan4GB()) { performCopyMoveOperationIfSufficientSpaceAvailable() } else { @@ -217,7 +217,7 @@ class CopyMoveFileHandler @Inject constructor( } } - fun handleCannotWrite4GbFileState() { + suspend fun handleCannotWrite4GbFileState() { if (isBookLessThan4GB()) { performCopyMoveOperationIfSufficientSpaceAvailable() } else { @@ -240,14 +240,12 @@ class CopyMoveFileHandler @Inject constructor( } } - fun performCopyMoveOperationIfSufficientSpaceAvailable() { - lifecycleScope?.launch { - val availableSpace = storageCalculator.availableBytes(File(sharedPreferenceUtil.prefStorage)) - if (hasNotSufficientStorageSpace(availableSpace)) { - fileCopyMoveCallback?.insufficientSpaceInStorage(availableSpace) - } else { - performCopyMoveOperation() - } + suspend fun performCopyMoveOperationIfSufficientSpaceAvailable() { + val availableSpace = storageCalculator.availableBytes(File(sharedPreferenceUtil.prefStorage)) + if (hasNotSufficientStorageSpace(availableSpace)) { + fileCopyMoveCallback?.insufficientSpaceInStorage(availableSpace) + } else { + performCopyMoveOperation() } } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/LocalLibraryFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/LocalLibraryFragment.kt index f2e8abbbc..c182e6ffe 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/LocalLibraryFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/LocalLibraryFragment.kt @@ -244,69 +244,72 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal ) } + @Suppress("LongMethod") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setUpSwipeRefreshLayout() - copyMoveFileHandler?.apply { - setFileCopyMoveCallback(this@LocalLibraryFragment) - setLifeCycleScope(lifecycleScope) - } - fragmentDestinationLibraryBinding?.zimfilelist?.run { - adapter = booksOnDiskAdapter - layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) - setHasFixedSize(true) - visibility = GONE - } - zimManageViewModel.fileSelectListStates.observe(viewLifecycleOwner, Observer(::render)) - .also { - coreMainActivity.navHostContainer - .setBottomMarginToFragmentContainerView(0) + lifecycleScope.launch { + setUpSwipeRefreshLayout() + copyMoveFileHandler?.apply { + setFileCopyMoveCallback(this@LocalLibraryFragment) + setLifeCycleScope(lifecycleScope) + } + fragmentDestinationLibraryBinding?.zimfilelist?.run { + adapter = booksOnDiskAdapter + layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) + setHasFixedSize(true) + visibility = GONE + } + zimManageViewModel.fileSelectListStates.observe(viewLifecycleOwner, Observer(::render)) + .also { + coreMainActivity.navHostContainer + .setBottomMarginToFragmentContainerView(0) - getBottomNavigationView()?.let { - setBottomMarginToSwipeRefreshLayout(it.measuredHeight) + getBottomNavigationView()?.let { + setBottomMarginToSwipeRefreshLayout(it.measuredHeight) + } + } + disposable.add(sideEffects()) + disposable.add(fileSelectActions()) + zimManageViewModel.deviceListScanningProgress.observe(viewLifecycleOwner) { + fragmentDestinationLibraryBinding?.scanningProgressView?.apply { + progress = it + // hide this progress bar when scanning is complete. + visibility = if (it == MAX_PROGRESS) GONE else VISIBLE + // enable if the previous scanning is completes. + fragmentDestinationLibraryBinding?.zimSwiperefresh?.isEnabled = it == MAX_PROGRESS } } - disposable.add(sideEffects()) - disposable.add(fileSelectActions()) - zimManageViewModel.deviceListScanningProgress.observe(viewLifecycleOwner) { - fragmentDestinationLibraryBinding?.scanningProgressView?.apply { - progress = it - // hide this progress bar when scanning is complete. - visibility = if (it == MAX_PROGRESS) GONE else VISIBLE - // enable if the previous scanning is completes. - fragmentDestinationLibraryBinding?.zimSwiperefresh?.isEnabled = it == MAX_PROGRESS + if (savedInstanceState != null && savedInstanceState.getBoolean(WAS_IN_ACTION_MODE)) { + zimManageViewModel.fileSelectActions.offer(FileSelectActions.RestartActionMode) } - } - if (savedInstanceState != null && savedInstanceState.getBoolean(WAS_IN_ACTION_MODE)) { - zimManageViewModel.fileSelectActions.offer(FileSelectActions.RestartActionMode) - } - fragmentDestinationLibraryBinding?.goToDownloadsButtonNoFiles?.setOnClickListener { - if (permissionDeniedLayoutShowing) { - permissionDeniedLayoutShowing = false - requireActivity().navigateToAppSettings() - } else { - offerAction(FileSelectActions.UserClickedDownloadBooksButton) + fragmentDestinationLibraryBinding?.goToDownloadsButtonNoFiles?.setOnClickListener { + if (permissionDeniedLayoutShowing) { + permissionDeniedLayoutShowing = false + requireActivity().navigateToAppSettings() + } else { + offerAction(FileSelectActions.UserClickedDownloadBooksButton) + } } - } - setUpFilePickerButton() + setUpFilePickerButton() - fragmentDestinationLibraryBinding?.zimfilelist?.addOnScrollListener( - SimpleRecyclerViewScrollListener { _, newState -> - when (newState) { - SCROLL_DOWN -> { - setBottomMarginToSwipeRefreshLayout(0) - } + fragmentDestinationLibraryBinding?.zimfilelist?.addOnScrollListener( + SimpleRecyclerViewScrollListener { _, newState -> + when (newState) { + SCROLL_DOWN -> { + setBottomMarginToSwipeRefreshLayout(0) + } - SCROLL_UP -> { - getBottomNavigationView()?.let { - setBottomMarginToSwipeRefreshLayout(it.measuredHeight) + SCROLL_UP -> { + getBottomNavigationView()?.let { + setBottomMarginToSwipeRefreshLayout(it.measuredHeight) + } } } } - } - ) - showCopyMoveDialogForOpenedZimFileFromStorage() + ) + showCopyMoveDialogForOpenedZimFileFromStorage() + } } private fun showCopyMoveDialogForOpenedZimFileFromStorage() { @@ -680,14 +683,16 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal private fun storeDeviceInPreferences( storageDevice: StorageDevice ) { - sharedPreferenceUtil.putPrefStorage( - sharedPreferenceUtil.getPublicDirectoryPath(storageDevice.name) - ) - sharedPreferenceUtil.putStoragePosition( - if (storageDevice.isInternal) INTERNAL_SELECT_POSITION - else EXTERNAL_SELECT_POSITION - ) - // after selecting the storage try to copy/move the zim file. - copyMoveFileHandler?.copyMoveZIMFileInSelectedStorage(storageDevice) + lifecycleScope.launch { + sharedPreferenceUtil.putPrefStorage( + sharedPreferenceUtil.getPublicDirectoryPath(storageDevice.name) + ) + sharedPreferenceUtil.putStoragePosition( + if (storageDevice.isInternal) INTERNAL_SELECT_POSITION + else EXTERNAL_SELECT_POSITION + ) + // after selecting the storage try to copy/move the zim file. + copyMoveFileHandler?.copyMoveZIMFileInSelectedStorage(storageDevice) + } } } diff --git a/app/src/test/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt b/app/src/test/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt index a8875e183..e472005f7 100644 --- a/app/src/test/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt +++ b/app/src/test/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt @@ -136,11 +136,11 @@ class CopyMoveFileHandlerTest { val result = fileHandler.validateZimFileCanCopyOrMove(storageFile) assertFalse(result) - verify { fileHandler.handleDetectingFileSystemState() } + coVerify { fileHandler.handleDetectingFileSystemState() } } @Test - fun validateZimFileCanCopyOrMoveShouldReturnFalseWhenCannotWrite4GbFile() = runBlocking { + fun validateZimFileCanCopyOrMoveShouldReturnFalseWhenCannotWrite4GbFile() = runTest { every { fileHandler.isBookLessThan4GB() } returns true every { fileHandler.showCopyMoveDialog() } just Runs every { @@ -151,23 +151,23 @@ class CopyMoveFileHandlerTest { val result = fileHandler.validateZimFileCanCopyOrMove(storageFile) assertFalse(result) - verify { fileHandler.handleCannotWrite4GbFileState() } + coVerify { fileHandler.handleCannotWrite4GbFileState() } } @Test - fun handleDetectingFileSystemStateShouldPerformCopyMoveOperationIfBookLessThan4GB() { + fun handleDetectingFileSystemStateShouldPerformCopyMoveOperationIfBookLessThan4GB() = runTest { fileHandler = spyk(fileHandler) prepareFileSystemAndFileForMockk() every { fileHandler.isBookLessThan4GB() } returns true - every { fileHandler.performCopyMoveOperationIfSufficientSpaceAvailable() } just Runs + coEvery { fileHandler.performCopyMoveOperationIfSufficientSpaceAvailable() } just Runs fileHandler.handleDetectingFileSystemState() - verify { fileHandler.performCopyMoveOperationIfSufficientSpaceAvailable() } + coVerify { fileHandler.performCopyMoveOperationIfSufficientSpaceAvailable() } } @Test - fun handleDetectingFileSystemStateShouldObserveFileSystemStateIfBookGreaterThan4GB() { + fun handleDetectingFileSystemStateShouldObserveFileSystemStateIfBookGreaterThan4GB() = runTest { fileHandler = spyk(fileHandler) prepareFileSystemAndFileForMockk(fileSystemState = DetectingFileSystem) every { fileHandler.isBookLessThan4GB() } returns false @@ -178,19 +178,19 @@ class CopyMoveFileHandlerTest { } @Test - fun handleCannotWrite4GbFileStateShouldPerformCopyMoveOperationIfBookLessThan4GB() { + fun handleCannotWrite4GbFileStateShouldPerformCopyMoveOperationIfBookLessThan4GB() = runTest { fileHandler = spyk(fileHandler) prepareFileSystemAndFileForMockk() every { fileHandler.isBookLessThan4GB() } returns true - every { fileHandler.performCopyMoveOperationIfSufficientSpaceAvailable() } just Runs + coEvery { fileHandler.performCopyMoveOperationIfSufficientSpaceAvailable() } just Runs fileHandler.handleCannotWrite4GbFileState() - verify { fileHandler.performCopyMoveOperationIfSufficientSpaceAvailable() } + coVerify { fileHandler.performCopyMoveOperationIfSufficientSpaceAvailable() } } @Test - fun handleCannotWrite4GbFileStateShouldCallCallbackIfBookGreaterThan4GB() { + fun handleCannotWrite4GbFileStateShouldCallCallbackIfBookGreaterThan4GB() = runTest { fileHandler = spyk(fileHandler) prepareFileSystemAndFileForMockk() every { fileHandler.isBookLessThan4GB() } returns false 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 8db3cd0f8..203c83e00 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 @@ -19,17 +19,12 @@ package org.kiwix.kiwixmobile.core.extensions import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import java.io.File suspend fun File.isFileExist(): Boolean = withContext(Dispatchers.IO) { exists() } -fun File.freeSpace(): Long = runBlocking { - withContext(Dispatchers.IO) { - freeSpace - } -} +suspend fun File.freeSpace(): Long = withContext(Dispatchers.IO) { freeSpace } suspend fun File.totalSpace(): Long = withContext(Dispatchers.IO) { totalSpace } diff --git a/custom/src/main/java/org/kiwix/kiwixmobile/custom/download/effects/SetPreferredStorageWithMostSpace.kt b/custom/src/main/java/org/kiwix/kiwixmobile/custom/download/effects/SetPreferredStorageWithMostSpace.kt index c7031a149..4924bd396 100644 --- a/custom/src/main/java/org/kiwix/kiwixmobile/custom/download/effects/SetPreferredStorageWithMostSpace.kt +++ b/custom/src/main/java/org/kiwix/kiwixmobile/custom/download/effects/SetPreferredStorageWithMostSpace.kt @@ -28,7 +28,7 @@ import javax.inject.Inject class SetPreferredStorageWithMostSpace @Inject constructor( private val storageCalculator: StorageCalculator, - private val sharedPreferenceUtil: SharedPreferenceUtil + private val sharedPreferenceUtil: SharedPreferenceUtil, ) : SideEffect { override fun invokeWith(activity: AppCompatActivity) { activity.lifecycleScope.launch {