Showing storage selection dialog at first time when copying/moving ZIM file

This commit is contained in:
MohitMaliFtechiz 2024-11-13 18:04:37 +05:30
parent 9c6267d05f
commit bd45f0e942
10 changed files with 98 additions and 46 deletions

View File

@ -30,6 +30,11 @@ import android.widget.TextView
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.FragmentManager
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 io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -43,6 +48,8 @@ import org.kiwix.kiwixmobile.core.extensions.deleteFile
import org.kiwix.kiwixmobile.core.extensions.isFileExist import org.kiwix.kiwixmobile.core.extensions.isFileExist
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.settings.StorageCalculator import org.kiwix.kiwixmobile.core.settings.StorageCalculator
import org.kiwix.kiwixmobile.core.utils.EXTERNAL_SELECT_POSITION
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
@ -74,6 +81,10 @@ class CopyMoveFileHandler @Inject constructor(
var isMoveOperation = false var isMoveOperation = false
var shouldValidateZimFile: Boolean = false var shouldValidateZimFile: Boolean = false
private var fileSystemDisposable: Disposable? = null private var fileSystemDisposable: Disposable? = null
private lateinit var fragmentManager: FragmentManager
private val storageDeviceList by lazy {
StorageDeviceUtils.getWritableStorage(activity)
}
private val copyMoveTitle: String by lazy { private val copyMoveTitle: String by lazy {
if (isMoveOperation) { if (isMoveOperation) {
@ -93,13 +104,24 @@ class CopyMoveFileHandler @Inject constructor(
fun showMoveFileToPublicDirectoryDialog( fun showMoveFileToPublicDirectoryDialog(
uri: Uri? = null, uri: Uri? = null,
documentFile: DocumentFile? = null, documentFile: DocumentFile? = null,
shouldValidateZimFile: Boolean = false shouldValidateZimFile: Boolean = false,
fragmentManager: FragmentManager
) { ) {
this.shouldValidateZimFile = shouldValidateZimFile this.shouldValidateZimFile = shouldValidateZimFile
this.fragmentManager = fragmentManager
setSelectedFileAndUri(uri, documentFile) setSelectedFileAndUri(uri, documentFile)
if (!sharedPreferenceUtil.copyMoveZimFilePermissionDialog) { if (sharedPreferenceUtil.shouldShowStorageSelectionDialog && storageDeviceList.size > 1) {
showMoveToPublicDirectoryPermissionDialog() // Show dialog to select storage if more than one storage device is available, and user
// have not configured the storage yet.
showCopyMoveDialog(true)
} else { } else {
if (storageDeviceList.size == 1) {
// If only internal storage is currently available, set shouldShowStorageSelectionDialog
// 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.
// This ensures they are prompted to configure storage settings upon SD card reinsertion.
sharedPreferenceUtil.shouldShowStorageSelectionDialog = true
}
if (validateZimFileCanCopyOrMove()) { if (validateZimFileCanCopyOrMove()) {
showCopyMoveDialog() showCopyMoveDialog()
} }
@ -107,8 +129,8 @@ class CopyMoveFileHandler @Inject constructor(
} }
fun setSelectedFileAndUri(uri: Uri?, documentFile: DocumentFile?) { fun setSelectedFileAndUri(uri: Uri?, documentFile: DocumentFile?) {
selectedFileUri = uri uri?.let { selectedFileUri = it }
selectedFile = documentFile documentFile?.let { selectedFile = it }
} }
fun setFileCopyMoveCallback(fileCopyMoveCallback: FileCopyMoveCallback?) { fun setFileCopyMoveCallback(fileCopyMoveCallback: FileCopyMoveCallback?) {
@ -119,22 +141,34 @@ class CopyMoveFileHandler @Inject constructor(
lifecycleScope = coroutineScope lifecycleScope = coroutineScope
} }
private fun showMoveToPublicDirectoryPermissionDialog() { private fun showStorageSelectDialog() = StorageSelectDialog()
alertDialogShower.show( .apply {
KiwixDialog.MoveFileToPublicDirectoryPermissionDialog, onSelectAction = ::copyMoveZIMFileInSelectedStorage
{ titleSize = STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
sharedPreferenceUtil.copyMoveZimFilePermissionDialog = true setStorageDeviceList(storageDeviceList)
if (validateZimFileCanCopyOrMove()) { setShouldShowCheckboxSelected(false)
performCopyOperation() }
} .show(
}, fragmentManager,
{ activity.getString(R.string.choose_storage_to_copy_move_zim_file)
sharedPreferenceUtil.copyMoveZimFilePermissionDialog = true
if (validateZimFileCanCopyOrMove()) {
performMoveOperation()
}
}
) )
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()) {
if (isMoveOperation) {
performMoveOperation()
} else {
performCopyOperation()
}
}
} }
fun isBookLessThan4GB(): Boolean = fun isBookLessThan4GB(): Boolean =
@ -192,22 +226,30 @@ class CopyMoveFileHandler @Inject constructor(
} }
} }
fun showCopyMoveDialog() { fun showCopyMoveDialog(showStorageSelectionDialog: Boolean = false) {
alertDialogShower.show( alertDialogShower.show(
KiwixDialog.CopyMoveFileToPublicDirectoryDialog, KiwixDialog.CopyMoveFileToPublicDirectoryDialog,
::performCopyOperation, { performCopyOperation(showStorageSelectionDialog) },
::performMoveOperation { performMoveOperation(showStorageSelectionDialog) }
) )
} }
fun performCopyOperation() { fun performCopyOperation(showStorageSelectionDialog: Boolean = false) {
isMoveOperation = false isMoveOperation = false
copyZimFileToPublicAppDirectory() if (showStorageSelectionDialog) {
showStorageSelectDialog()
} else {
copyZimFileToPublicAppDirectory()
}
} }
fun performMoveOperation() { fun performMoveOperation(showStorageSelectionDialog: Boolean = false) {
isMoveOperation = true isMoveOperation = true
moveZimFileToPublicAppDirectory() if (showStorageSelectionDialog) {
showStorageSelectDialog()
} else {
moveZimFileToPublicAppDirectory()
}
} }
private fun copyZimFileToPublicAppDirectory() { private fun copyZimFileToPublicAppDirectory() {

View File

@ -431,7 +431,8 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
uri, uri,
documentFile, documentFile,
// pass if fileName is null then we will validate it after copying/moving // pass if fileName is null then we will validate it after copying/moving
fileName == null fileName == null,
parentFragmentManager
) )
} else { } else {
getZimFileFromUri(uri)?.let(::navigateToReaderFragment) getZimFileFromUri(uri)?.let(::navigateToReaderFragment)
@ -669,6 +670,7 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
.apply { .apply {
onSelectAction = ::storeDeviceInPreferences onSelectAction = ::storeDeviceInPreferences
setStorageDeviceList(storageDeviceList) setStorageDeviceList(storageDeviceList)
setShouldShowCheckboxSelected(true)
} }
.show(parentFragmentManager, getString(string.pref_storage)) .show(parentFragmentManager, getString(string.pref_storage))
@ -683,6 +685,6 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
else EXTERNAL_SELECT_POSITION else EXTERNAL_SELECT_POSITION
) )
// after selecting the storage try to copy/move the zim file. // after selecting the storage try to copy/move the zim file.
copyMoveFileHandler?.showMoveFileToPublicDirectoryDialog() copyMoveFileHandler?.copyMoveZIMFileInSelectedStorage(storageDevice)
} }
} }

View File

@ -577,6 +577,7 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
onSelectAction = ::storeDeviceInPreferences onSelectAction = ::storeDeviceInPreferences
titleSize = STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE titleSize = STORAGE_SELECT_STORAGE_TITLE_TEXTVIEW_SIZE
setStorageDeviceList(storageDeviceList) setStorageDeviceList(storageDeviceList)
setShouldShowCheckboxSelected(false)
} }
.show(parentFragmentManager, getString(string.choose_storage_to_download_book)) .show(parentFragmentManager, getString(string.choose_storage_to_download_book))

View File

@ -230,15 +230,15 @@ class CopyMoveFileHandlerTest {
fileHandler.showMoveFileToPublicDirectoryDialog() fileHandler.showMoveFileToPublicDirectoryDialog()
every { fileHandler.validateZimFileCanCopyOrMove() } returns true every { fileHandler.validateZimFileCanCopyOrMove() } returns true
every { fileHandler.performCopyOperation() } just Runs every { fileHandler.performCopyOperation(showStorageSelectionDialog) } just Runs
positiveButtonClickSlot.captured.invoke() positiveButtonClickSlot.captured.invoke()
verify { fileHandler.performCopyOperation() } verify { fileHandler.performCopyOperation(showStorageSelectionDialog) }
every { sharedPreferenceUtil.copyMoveZimFilePermissionDialog } returns false every { sharedPreferenceUtil.copyMoveZimFilePermissionDialog } returns false
every { fileHandler.performMoveOperation() } just Runs every { fileHandler.performMoveOperation(showStorageSelectionDialog) } just Runs
negativeButtonClickSlot.captured.invoke() negativeButtonClickSlot.captured.invoke()
verify { fileHandler.performMoveOperation() } verify { fileHandler.performMoveOperation(showStorageSelectionDialog) }
verify { sharedPreferenceUtil.copyMoveZimFilePermissionDialog = true } verify { sharedPreferenceUtil.copyMoveZimFilePermissionDialog = true }
} }
@ -275,14 +275,14 @@ class CopyMoveFileHandlerTest {
every { fileHandler.validateZimFileCanCopyOrMove() } returns true every { fileHandler.validateZimFileCanCopyOrMove() } returns true
fileHandler.showMoveFileToPublicDirectoryDialog() fileHandler.showMoveFileToPublicDirectoryDialog()
every { fileHandler.performCopyOperation() } just Runs every { fileHandler.performCopyOperation(showStorageSelectionDialog) } just Runs
positiveButtonClickSlot.captured.invoke() positiveButtonClickSlot.captured.invoke()
verify { fileHandler.performCopyOperation() } verify { fileHandler.performCopyOperation(showStorageSelectionDialog) }
every { fileHandler.performMoveOperation() } just Runs every { fileHandler.performMoveOperation(showStorageSelectionDialog) } just Runs
negativeButtonClickSlot.captured.invoke() negativeButtonClickSlot.captured.invoke()
verify { fileHandler.performMoveOperation() } verify { fileHandler.performMoveOperation(showStorageSelectionDialog) }
} }
private fun prepareFileSystemAndFileForMockk( private fun prepareFileSystemAndFileForMockk(

View File

@ -50,13 +50,14 @@ class StorageSelectDialog : DialogFragment() {
private var aTitle: String? = null private var aTitle: String? = null
private var storageSelectDialogViewBinding: StorageSelectDialogBinding? = null private var storageSelectDialogViewBinding: StorageSelectDialogBinding? = null
private val storageDeviceList = arrayListOf<StorageDevice>() private val storageDeviceList = arrayListOf<StorageDevice>()
private var shouldShowCheckboxSelected: Boolean = true
private val storageAdapter: StorageAdapter by lazy { private val storageAdapter: StorageAdapter by lazy {
StorageAdapter( StorageAdapter(
StorageDelegate( StorageDelegate(
storageCalculator, storageCalculator,
sharedPreferenceUtil, sharedPreferenceUtil,
aTitle == getString(R.string.choose_storage_to_download_book) shouldShowCheckboxSelected
) { ) {
onSelectAction?.invoke(it) onSelectAction?.invoke(it)
dismiss() dismiss()
@ -68,6 +69,10 @@ class StorageSelectDialog : DialogFragment() {
this.storageDeviceList.addAll(storageDeviceList) this.storageDeviceList.addAll(storageDeviceList)
} }
fun setShouldShowCheckboxSelected(shouldShowCheckboxSelected: Boolean) {
this.shouldShowCheckboxSelected = shouldShowCheckboxSelected
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,

View File

@ -30,7 +30,7 @@ import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
class StorageDelegate( class StorageDelegate(
private val storageCalculator: StorageCalculator, private val storageCalculator: StorageCalculator,
private val sharedPreferenceUtil: SharedPreferenceUtil, private val sharedPreferenceUtil: SharedPreferenceUtil,
private val isShowingStorageOptionForFirstDownload: Boolean, private val shouldShowCheckboxSelected: Boolean,
private val onClickAction: (StorageDevice) -> Unit private val onClickAction: (StorageDevice) -> Unit
) : AdapterDelegate<StorageDevice> { ) : AdapterDelegate<StorageDevice> {
override fun createViewHolder(parent: ViewGroup): ViewHolder { override fun createViewHolder(parent: ViewGroup): ViewHolder {
@ -38,7 +38,7 @@ class StorageDelegate(
parent.viewBinding(ItemStoragePreferenceBinding::inflate, false), parent.viewBinding(ItemStoragePreferenceBinding::inflate, false),
storageCalculator, storageCalculator,
sharedPreferenceUtil, sharedPreferenceUtil,
isShowingStorageOptionForFirstDownload, shouldShowCheckboxSelected,
onClickAction onClickAction
) )
} }

View File

@ -44,7 +44,7 @@ internal class StorageViewHolder(
private val itemStoragePreferenceBinding: ItemStoragePreferenceBinding, private val itemStoragePreferenceBinding: ItemStoragePreferenceBinding,
private val storageCalculator: StorageCalculator, private val storageCalculator: StorageCalculator,
private val sharedPreferenceUtil: SharedPreferenceUtil, private val sharedPreferenceUtil: SharedPreferenceUtil,
private val isShowingStorageOptionForFirstDownload: Boolean, private val shouldShowCheckboxSelected: Boolean,
private val onClickAction: (StorageDevice) -> Unit private val onClickAction: (StorageDevice) -> Unit
) : BaseViewHolder<StorageDevice>(itemStoragePreferenceBinding.root) { ) : BaseViewHolder<StorageDevice>(itemStoragePreferenceBinding.root) {
@ -60,7 +60,7 @@ internal class StorageViewHolder(
) )
) )
radioButton.isChecked = !isShowingStorageOptionForFirstDownload && radioButton.isChecked = shouldShowCheckboxSelected &&
adapterPosition == sharedPreferenceUtil.storagePosition adapterPosition == sharedPreferenceUtil.storagePosition
freeSpace.apply { freeSpace.apply {
text = item.getFreeSpace(root.context, storageCalculator) text = item.getFreeSpace(root.context, storageCalculator)

View File

@ -257,11 +257,11 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) {
_textZooms.offer(textZoom) _textZooms.offer(textZoom)
} }
var copyMoveZimFilePermissionDialog: Boolean var shouldShowStorageSelectionDialog: Boolean
get() = sharedPreferences.getBoolean(PREF_COPY_MOVE_PERMISSION, false) get() = sharedPreferences.getBoolean(PREF_SHOW_COPY_MOVE_STORAGE_SELECTION_DIALOG, true)
set(value) { set(value) {
sharedPreferences.edit { sharedPreferences.edit {
putBoolean(PREF_COPY_MOVE_PERMISSION, value) putBoolean(PREF_SHOW_COPY_MOVE_STORAGE_SELECTION_DIALOG, value)
} }
} }
@ -329,7 +329,7 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) {
const val PREF_HISTORY_MIGRATED = "pref_history_migrated" const val PREF_HISTORY_MIGRATED = "pref_history_migrated"
const val PREF_NOTES_MIGRATED = "pref_notes_migrated" const val PREF_NOTES_MIGRATED = "pref_notes_migrated"
const val PREF_APP_DIRECTORY_TO_PUBLIC_MIGRATED = "pref_app_directory_to_public_migrated" const val PREF_APP_DIRECTORY_TO_PUBLIC_MIGRATED = "pref_app_directory_to_public_migrated"
const val PREF_COPY_MOVE_PERMISSION = "pref_copy_move_permission" const val PREF_SHOW_COPY_MOVE_STORAGE_SELECTION_DIALOG = "pref_show_copy_move_storage_dialog"
private const val PREF_LATER_CLICKED_MILLIS = "pref_later_clicked_millis" private const val PREF_LATER_CLICKED_MILLIS = "pref_later_clicked_millis"
const val PREF_LAST_DONATION_POPUP_SHOWN_IN_MILLISECONDS = const val PREF_LAST_DONATION_POPUP_SHOWN_IN_MILLISECONDS =
"pref_last_donation_shown_in_milliseconds" "pref_last_donation_shown_in_milliseconds"

View File

@ -123,6 +123,7 @@ sealed class KiwixDialog(
R.string.copy_move_files_dialog_description, R.string.copy_move_files_dialog_description,
R.string.action_copy, R.string.action_copy,
R.string.move, R.string.move,
neutralMessage = R.string.cancel,
cancelable = false cancelable = false
) )

View File

@ -331,6 +331,7 @@
<string name="copy_file_error_message">Error in copying the ZIM file: %s.</string> <string name="copy_file_error_message">Error in copying the ZIM file: %s.</string>
<string name="move_files_permission_dialog_title">Move/Copy files to app public directory?</string> <string name="move_files_permission_dialog_title">Move/Copy files to app public directory?</string>
<string name="move_files_permission_dialog_description">Due to Google Play policies on Android 11 and above, our app can no longer directly access files stored elsewhere on your device. To let you view your selected files, we need to move or copy them into a special folder within our application directory. This allows us to access and open the files. Do you agree to this?</string> <string name="move_files_permission_dialog_description">Due to Google Play policies on Android 11 and above, our app can no longer directly access files stored elsewhere on your device. To let you view your selected files, we need to move or copy them into a special folder within our application directory. This allows us to access and open the files. Do you agree to this?</string>
<string name="choose_storage_to_copy_move_zim_file">Choose storage to copy/move ZIM file</string>
<string name="move_file_error_message">Error in moving the ZIM file: %s.</string> <string name="move_file_error_message">Error in moving the ZIM file: %s.</string>
<string name="how_to_update_content">How to update content?</string> <string name="how_to_update_content">How to update content?</string>
<string name="update_content_description">To update content (a ZIM file) you need to download the full latest version of this very same content. You can do that via the download section.</string> <string name="update_content_description">To update content (a ZIM file) you need to download the full latest version of this very same content. You can do that via the download section.</string>