diff --git a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt index d562b38b2..41bc521db 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt @@ -33,6 +33,7 @@ import androidx.core.os.ConfigurationCompat import androidx.core.os.bundleOf import androidx.core.view.isVisible import androidx.drawerlayout.widget.DrawerLayout +import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController import androidx.navigation.NavDestination import androidx.navigation.fragment.NavHostFragment @@ -40,6 +41,7 @@ import androidx.navigation.ui.NavigationUI import androidx.navigation.ui.setupWithNavController import com.google.android.material.navigation.NavigationView import eu.mhutti1.utils.storage.StorageDeviceUtils +import kotlinx.coroutines.launch import org.kiwix.kiwixmobile.BuildConfig import org.kiwix.kiwixmobile.R import org.kiwix.kiwixmobile.core.R.id @@ -126,13 +128,15 @@ class KiwixMainActivity : CoreMainActivity() { onNavigationItemSelected(item) } activityKiwixMainBinding.bottomNavView.setupWithNavController(navController) - migrateInternalToPublicAppDirectory() + lifecycleScope.launch { + migrateInternalToPublicAppDirectory() + } handleZimFileIntent(intent) handleNotificationIntent(intent) handleGetContentIntent(intent) } - private fun migrateInternalToPublicAppDirectory() { + private suspend fun migrateInternalToPublicAppDirectory() { if (!sharedPreferenceUtil.prefIsAppDirectoryMigrated) { val storagePath = StorageDeviceUtils.getWritableStorage(this) .getOrNull(sharedPreferenceUtil.storagePosition) 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 9ba5df0a4..103875f00 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 @@ -501,7 +501,7 @@ class CopyMoveFileHandler @Inject constructor( @SuppressLint("InflateParams") fun showPreparingCopyMoveDialog() { if (copyMovePreparingDialog == null) { val dialogView: View = - activity.layoutInflater.inflate(layout.item_custom_spinner, null) + activity.layoutInflater.inflate(R.layout.item_custom_spinner, null) copyMovePreparingDialog = alertDialogShower.create(KiwixDialog.PreparingCopyingFilesDialog { dialogView }) } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt index cfba5eab5..4ae5e285c 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/settings/KiwixPrefsFragment.kt @@ -39,11 +39,14 @@ import org.kiwix.kiwixmobile.core.extensions.storagePathAndTitle import org.kiwix.kiwixmobile.core.extensions.usedPercentage import org.kiwix.kiwixmobile.core.navigateToSettings import org.kiwix.kiwixmobile.core.settings.CorePrefsFragment +import org.kiwix.kiwixmobile.core.settings.StorageLoadingPreference import org.kiwix.kiwixmobile.core.settings.StorageRadioButtonPreference 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_INTERNAL_STORAGE +const val PREF_STORAGE_PROGRESSBAR = "storage_progressbar" + class KiwixPrefsFragment : CorePrefsFragment() { private var storageDisposable: Disposable? = null private var storageDeviceList: List = listOf() @@ -56,10 +59,12 @@ class KiwixPrefsFragment : CorePrefsFragment() { override suspend fun setStorage() { sharedPreferenceUtil?.let { - if (storageDisposable?.isDisposed == false) { + if (storageDeviceList.isNotEmpty()) { // update the storage when user switch to other storage. setUpStoragePreference(it) + return@setStorage } + showHideProgressBarWhileFetchingStorageInfo(true) storageDisposable = Flowable.fromCallable { StorageDeviceUtils.getWritableStorage(requireActivity()) } .subscribeOn(Schedulers.io()) @@ -67,6 +72,8 @@ class KiwixPrefsFragment : CorePrefsFragment() { .subscribe( { storageList -> storageDeviceList = storageList + showHideProgressBarWhileFetchingStorageInfo(false) + showInternalStoragePreferece() showExternalPreferenceIfAvailable() setUpStoragePreference(it) }, @@ -75,6 +82,20 @@ class KiwixPrefsFragment : CorePrefsFragment() { } } + /** + * Shows or hides the progress bar while the application is fetching + * storage information in the background. The progress bar is displayed + * with a title indicating that the storage information is being retrieved. + * + * @param show If true, the progress bar will be displayed; otherwise, it will be hidden. + */ + private fun showHideProgressBarWhileFetchingStorageInfo(show: Boolean) { + findPreference(PREF_STORAGE_PROGRESSBAR)?.apply { + isVisible = show + setTitle(getString(R.string.fetching_storage_info)) + } + } + private fun setUpStoragePreference(sharedPreferenceUtil: SharedPreferenceUtil) { lifecycleScope.launch { storageDeviceList.forEachIndexed { index, storageDevice -> @@ -100,6 +121,10 @@ class KiwixPrefsFragment : CorePrefsFragment() { } } + private fun showInternalStoragePreferece() { + findPreference(PREF_INTERNAL_STORAGE)?.isVisible = true + } + private fun showExternalPreferenceIfAvailable() { findPreference(PREF_EXTERNAL_STORAGE)?.isVisible = storageDeviceList.size > 1 diff --git a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostFragment.kt index f7b4743e2..dc9998561 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostFragment.kt @@ -276,7 +276,7 @@ class ZimHostFragment : BaseFragment(), ZimHostCallbacks, ZimHostContract.View { private fun startKiwixHotspot() { if (dialog == null) { val dialogView: View = - layoutInflater.inflate(layout.item_custom_spinner, null) + layoutInflater.inflate(R.layout.item_custom_spinner, null) dialog = alertDialogShower.create(StartServer { dialogView }) } dialog?.show() diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/StorageLoadingPreference.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/StorageLoadingPreference.kt new file mode 100644 index 000000000..622a08b5e --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/StorageLoadingPreference.kt @@ -0,0 +1,122 @@ +/* + * Kiwix Android + * Copyright (c) 2O24 Kiwix + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package org.kiwix.kiwixmobile.core.settings + +import android.content.Context +import android.util.AttributeSet +import android.view.View.VISIBLE +import android.widget.ProgressBar +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet +import androidx.preference.Preference +import androidx.preference.PreferenceViewHolder +import org.kiwix.kiwixmobile.core.R +import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO + +const val MARGIN_TOP = 8 + +class StorageLoadingPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = ZERO +) : Preference(context, attrs, defStyleAttr) { + + private var customProgressTitle: TextView? = null + private var progressBarTitleText: String? = null + + init { + widgetLayoutResource = R.layout.item_custom_spinner + } + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + val progressBar = holder.findViewById(R.id.custom_progressbar) as? ProgressBar + customProgressTitle = holder.findViewById(R.id.custom_progress_title) as TextView + progressBarTitleText?.let(::setProgressBarTitle) + + val constraintLayout = holder.itemView as ConstraintLayout + val constraintSet = ConstraintSet() + constraintSet.clone(constraintLayout) + + constraintSet.connect( + progressBar?.id ?: ZERO, + ConstraintSet.START, + ConstraintSet.PARENT_ID, + ConstraintSet.START, + ZERO + ) + constraintSet.connect( + progressBar?.id ?: ZERO, + ConstraintSet.END, + ConstraintSet.PARENT_ID, + ConstraintSet.END, + ZERO + ) + constraintSet.connect( + progressBar?.id ?: ZERO, + ConstraintSet.TOP, + ConstraintSet.PARENT_ID, + ConstraintSet.TOP, + ZERO + ) + + constraintSet.connect( + customProgressTitle?.id ?: ZERO, + ConstraintSet.START, + ConstraintSet.PARENT_ID, + ConstraintSet.START, + ZERO + ) + constraintSet.connect( + customProgressTitle?.id ?: ZERO, + ConstraintSet.END, + ConstraintSet.PARENT_ID, + ConstraintSet.END, + ZERO + ) + constraintSet.connect( + customProgressTitle?.id ?: ZERO, + ConstraintSet.TOP, + progressBar?.id ?: ZERO, + ConstraintSet.BOTTOM, + MARGIN_TOP + ) + constraintSet.connect( + customProgressTitle?.id ?: ZERO, + ConstraintSet.BOTTOM, + ConstraintSet.PARENT_ID, + ConstraintSet.BOTTOM, + ZERO + ) + constraintSet.applyTo(constraintLayout) + } + + fun setTitle(title: String) { + progressBarTitleText = title + setProgressBarTitle(title) + } + + private fun setProgressBarTitle(title: String) { + customProgressTitle?.apply { + text = title + visibility = VISIBLE + } + } +} diff --git a/app/src/main/res/layout/item_custom_spinner.xml b/core/src/main/res/layout/item_custom_spinner.xml similarity index 72% rename from app/src/main/res/layout/item_custom_spinner.xml rename to core/src/main/res/layout/item_custom_spinner.xml index 2d8754ce1..76943fb0c 100644 --- a/app/src/main/res/layout/item_custom_spinner.xml +++ b/core/src/main/res/layout/item_custom_spinner.xml @@ -20,9 +20,10 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="16dp"> + android:padding="@dimen/activity_horizontal_margin"> + diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 0ca3e5b84..ba1ff3d83 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -138,6 +138,7 @@ • Other contents like Wikileaks or Wikisource are also available You can either download your chosen ZIM files in-app or carefully select the one(s) you want and download from a Desktop computer before transferring the ZIM files to your SD card. ZIM files download in-app are located in the external storage directory in a folder entitled Kiwix. + Fetching storage details… Storage Current Folder %s used diff --git a/core/src/main/res/xml/preferences.xml b/core/src/main/res/xml/preferences.xml index 9caa1118e..e7e2bc365 100644 --- a/core/src/main/res/xml/preferences.xml +++ b/core/src/main/res/xml/preferences.xml @@ -65,15 +65,23 @@ app:iconSpaceReserved="false" app:title="@string/pref_storage"> + + + app:iconSpaceReserved="false" + app:isPreferenceVisible="false" /> + app:iconSpaceReserved="false" + app:isPreferenceVisible="false" />