mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
Improved the visibility of permissionDeniedLayout
when permission is denied.
* Improved the display of the ZIM file list when permission is granted. * Displaying the snackBar with Compose UI when there is not enough storage to copy the ZIM file. * Created the `SwipeRefreshLayout` according to our theme, along with custom logic to enable or disable it, since the default PullToRefresh does not support this feature. * Created `ContentLoadingProgressBar` to show circular and horizontal progress bars with progress, styled according to our theme.
This commit is contained in:
parent
de46b8f0dd
commit
5b507d8f3d
@ -30,7 +30,7 @@ import org.kiwix.kiwixmobile.intro.IntroModule
|
||||
import org.kiwix.kiwixmobile.language.LanguageFragment
|
||||
import org.kiwix.kiwixmobile.localFileTransfer.LocalFileTransferFragment
|
||||
import org.kiwix.kiwixmobile.main.KiwixMainActivity
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.LocalLibraryFragment
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.local.LocalLibraryFragment
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.OnlineLibraryFragment
|
||||
import org.kiwix.kiwixmobile.nav.destination.reader.KiwixReaderFragment
|
||||
import org.kiwix.kiwixmobile.settings.KiwixSettingsFragment
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2020 Kiwix <android.kiwix.org>
|
||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||
* 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
|
||||
@ -16,7 +16,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.nav.destination.library
|
||||
package org.kiwix.kiwixmobile.nav.destination.library.local
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity.RESULT_OK
|
||||
@ -30,8 +30,6 @@ import android.os.Environment
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
@ -67,6 +65,7 @@ import org.kiwix.kiwixmobile.cachedComponent
|
||||
import org.kiwix.kiwixmobile.core.R.string
|
||||
import org.kiwix.kiwixmobile.core.base.BaseActivity
|
||||
import org.kiwix.kiwixmobile.core.base.BaseFragment
|
||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isManageExternalStoragePermissionGranted
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.navigate
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.viewModel
|
||||
@ -100,6 +99,7 @@ import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDis
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
|
||||
import org.kiwix.kiwixmobile.databinding.FragmentDestinationLibraryBinding
|
||||
import org.kiwix.kiwixmobile.main.KiwixMainActivity
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.CopyMoveFileHandler
|
||||
import org.kiwix.kiwixmobile.zimManager.MAX_PROGRESS
|
||||
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel
|
||||
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel.FileSelectActions
|
||||
@ -151,6 +151,18 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
*/
|
||||
private var noFilesViewItem = mutableStateOf(Triple("", "", false))
|
||||
|
||||
/**
|
||||
* This is a Pair which is responsible for showing and hiding the "Pull to refresh"
|
||||
* animation.
|
||||
*
|
||||
* A [Pair] containing:
|
||||
* - [Boolean]: The first boolean triggers/hide the "pull to refresh" animation.
|
||||
* - [Boolean]: The second boolean enable/disable the "pull to refresh".
|
||||
*/
|
||||
private var swipeRefreshItem = mutableStateOf(Pair(false, true))
|
||||
|
||||
private var scanningProgressItem = mutableStateOf(Pair(false, ZERO))
|
||||
|
||||
private val zimManageViewModel by lazy {
|
||||
requireActivity().viewModel<ZimManageViewModel>(viewModelFactory)
|
||||
}
|
||||
@ -159,20 +171,14 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.RequestMultiplePermissions()
|
||||
) { permissionResult ->
|
||||
val isGranted =
|
||||
permissionResult.entries.all(
|
||||
Map.Entry<String, @kotlin.jvm.JvmSuppressWildcards Boolean>::value
|
||||
)
|
||||
if (readStorageHasBeenPermanentlyDenied(isGranted)) {
|
||||
permissionDeniedLayoutShowing = true
|
||||
noFilesViewItem.value = Triple(
|
||||
requireActivity().resources.getString(string.grant_read_storage_permission),
|
||||
requireActivity().resources.getString(string.go_to_settings_label),
|
||||
true
|
||||
)
|
||||
} else if (isGranted) {
|
||||
permissionDeniedLayoutShowing = false
|
||||
}
|
||||
val isGranted = permissionResult.values.all { it }
|
||||
val isPermanentlyDenied = readStorageHasBeenPermanentlyDenied(isGranted)
|
||||
permissionDeniedLayoutShowing = isPermanentlyDenied
|
||||
noFilesViewItem.value = Triple(
|
||||
requireActivity().resources.getString(string.grant_read_storage_permission),
|
||||
requireActivity().resources.getString(string.go_to_settings_label),
|
||||
isPermanentlyDenied
|
||||
)
|
||||
}
|
||||
|
||||
override fun inject(baseActivity: BaseActivity) {
|
||||
@ -198,10 +204,11 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
onClick = { onBookItemClick(it) },
|
||||
onLongClick = { onBookItemLongClick(it) },
|
||||
onMultiSelect = { offerAction(RequestSelect(it)) },
|
||||
onRefresh = {},
|
||||
swipeRefreshItem = true to true,
|
||||
onRefresh = { onSwipeRefresh() },
|
||||
swipeRefreshItem = swipeRefreshItem.value,
|
||||
noFilesViewItem = noFilesViewItem.value,
|
||||
onDownloadButtonClick = { downloadBookButtonClick() }
|
||||
onDownloadButtonClick = { downloadBookButtonClick() },
|
||||
scanningProgressItem = scanningProgressItem.value
|
||||
) {
|
||||
NavigationIcon(
|
||||
iconItem = IconItem.Vector(Icons.Filled.Menu),
|
||||
@ -255,7 +262,6 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setUpSwipeRefreshLayout()
|
||||
copyMoveFileHandler?.apply {
|
||||
setFileCopyMoveCallback(this@LocalLibraryFragment)
|
||||
setLifeCycleScope(lifecycleScope)
|
||||
@ -272,13 +278,10 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
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
|
||||
}
|
||||
// hide this progress bar when scanning is complete.
|
||||
scanningProgressItem.value = Pair(it != MAX_PROGRESS, it)
|
||||
// enable if the previous scanning is completes.
|
||||
swipeRefreshItem.value = Pair(false, it == MAX_PROGRESS)
|
||||
}
|
||||
if (savedInstanceState != null && savedInstanceState.getBoolean(WAS_IN_ACTION_MODE)) {
|
||||
zimManageViewModel.fileSelectActions.offer(FileSelectActions.RestartActionMode)
|
||||
@ -319,32 +322,26 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
requireArguments().clear()
|
||||
}
|
||||
|
||||
private fun setUpSwipeRefreshLayout() {
|
||||
fragmentDestinationLibraryBinding?.zimSwiperefresh?.setOnRefreshListener {
|
||||
if (permissionDeniedLayoutShowing) {
|
||||
fragmentDestinationLibraryBinding?.zimSwiperefresh?.isRefreshing = false
|
||||
private fun onSwipeRefresh() {
|
||||
if (permissionDeniedLayoutShowing) {
|
||||
// When permission denied layout is showing hide the "Swipe refresh".
|
||||
swipeRefreshItem.value = false to true
|
||||
} else {
|
||||
if (!requireActivity().isManageExternalStoragePermissionGranted(sharedPreferenceUtil)) {
|
||||
showManageExternalStoragePermissionDialog()
|
||||
// Set loading to false since the dialog is currently being displayed.
|
||||
// If the user clicks on "No" in the permission dialog,
|
||||
// the loading icon remains visible infinitely.
|
||||
swipeRefreshItem.value = false to true
|
||||
} else {
|
||||
if (!requireActivity().isManageExternalStoragePermissionGranted(sharedPreferenceUtil)) {
|
||||
showManageExternalStoragePermissionDialog()
|
||||
// Set loading to false since the dialog is currently being displayed.
|
||||
// If the user clicks on "No" in the permission dialog,
|
||||
// the loading icon remains visible infinitely.
|
||||
fragmentDestinationLibraryBinding?.zimSwiperefresh?.isRefreshing = false
|
||||
} else {
|
||||
fragmentDestinationLibraryBinding?.zimSwiperefresh?.apply {
|
||||
// hide the swipe refreshing because now we are showing the ContentLoadingProgressBar
|
||||
// to show the progress of how many files are scanned.
|
||||
isRefreshing = false
|
||||
// disable the swipe refresh layout until the ongoing scanning will not complete
|
||||
// to avoid multiple scanning.
|
||||
isEnabled = false
|
||||
}
|
||||
fragmentDestinationLibraryBinding?.scanningProgressView?.apply {
|
||||
visibility = VISIBLE
|
||||
progress = 0
|
||||
}
|
||||
requestFileSystemCheck()
|
||||
}
|
||||
// hide the swipe refreshing because now we are showing the ContentLoadingProgressBar
|
||||
// to show the progress of how many files are scanned.
|
||||
// disable the swipe refresh layout until the ongoing scanning will not complete
|
||||
// to avoid multiple scanning.
|
||||
swipeRefreshItem.value = false to false
|
||||
// Show the progress Bar.
|
||||
scanningProgressItem.value = true to ZERO
|
||||
requestFileSystemCheck()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -394,7 +391,7 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
}
|
||||
try {
|
||||
fileSelectLauncher.launch(Intent.createChooser(intent, "Select a zim file"))
|
||||
} catch (ex: ActivityNotFoundException) {
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
activity.toast(resources.getString(R.string.no_app_found_to_open), Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
@ -450,7 +447,7 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
}
|
||||
|
||||
private fun isValidZimFile(fileName: String): Boolean =
|
||||
FileUtils.isValidZimFile(fileName) || FileUtils.isSplittedZimFile(fileName)
|
||||
FileUtils.isValidZimFile(fileName) || isSplittedZimFile(fileName)
|
||||
|
||||
private suspend fun getZimFileFromUri(
|
||||
uri: Uri
|
||||
@ -513,7 +510,11 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
) {
|
||||
checkPermissions()
|
||||
} else if (!permissionDeniedLayoutShowing) {
|
||||
fragmentDestinationLibraryBinding?.zimfilelist?.visibility = VISIBLE
|
||||
noFilesViewItem.value = Triple(
|
||||
requireActivity().resources.getString(string.no_files_here),
|
||||
requireActivity().resources.getString(string.download_books),
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,8 +522,6 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
super.onDestroyView()
|
||||
mainRepositoryActions.dispose()
|
||||
actionMode = null
|
||||
fragmentDestinationLibraryBinding?.zimfilelist?.adapter = null
|
||||
fragmentDestinationLibraryBinding = null
|
||||
disposable.clear()
|
||||
storagePermissionLauncher?.unregister()
|
||||
storagePermissionLauncher = null
|
||||
@ -680,11 +679,11 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
}
|
||||
|
||||
private fun showStorageSelectionSnackBar(message: String) {
|
||||
fragmentDestinationLibraryBinding?.zimfilelist?.snack(
|
||||
message,
|
||||
requireActivity().findViewById(R.id.bottom_nav_view),
|
||||
string.download_change_storage,
|
||||
{
|
||||
snackBarHostState.snack(
|
||||
message = message,
|
||||
actionLabel = getString(string.download_change_storage),
|
||||
lifecycleScope = lifecycleScope,
|
||||
actionClick = {
|
||||
lifecycleScope.launch {
|
||||
showStorageSelectDialog((requireActivity() as KiwixMainActivity).getStorageDeviceList())
|
||||
}
|
||||
@ -738,7 +737,7 @@ class LocalLibraryFragment : BaseFragment(), CopyMoveFileHandler.FileCopyMoveCal
|
||||
) { permissionResult ->
|
||||
val isGranted =
|
||||
permissionResult.entries.all(
|
||||
Map.Entry<String, @kotlin.jvm.JvmSuppressWildcards Boolean>::value
|
||||
Map.Entry<String, @JvmSuppressWildcards Boolean>::value
|
||||
)
|
||||
if (isGranted) {
|
||||
zimFileUri?.let {
|
@ -16,10 +16,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.nav.destination.library
|
||||
package org.kiwix.kiwixmobile.nav.destination.library.local
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -43,9 +42,12 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import org.kiwix.kiwixmobile.R.string
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar
|
||||
import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar
|
||||
import org.kiwix.kiwixmobile.core.ui.components.KiwixButton
|
||||
import org.kiwix.kiwixmobile.core.ui.components.KiwixSnackbarHost
|
||||
import org.kiwix.kiwixmobile.core.ui.components.ProgressBarStyle
|
||||
import org.kiwix.kiwixmobile.core.ui.components.SwipeRefreshLayout
|
||||
import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.Black
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.KiwixTheme
|
||||
@ -60,13 +62,14 @@ import org.kiwix.kiwixmobile.ui.ZimFilesLanguageHeader
|
||||
import org.kiwix.kiwixmobile.zimManager.fileselectView.FileSelectListState
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Suppress("ComposableLambdaParameterNaming", "LongParameterList", "UnusedParameter")
|
||||
@Suppress("ComposableLambdaParameterNaming", "LongParameterList")
|
||||
@Composable
|
||||
fun LocalLibraryScreen(
|
||||
state: FileSelectListState,
|
||||
snackBarHostState: SnackbarHostState,
|
||||
swipeRefreshItem: Pair<Boolean, Boolean>,
|
||||
onRefresh: () -> Unit,
|
||||
scanningProgressItem: Pair<Boolean, Int>,
|
||||
noFilesViewItem: Triple<String, String, Boolean>,
|
||||
onDownloadButtonClick: () -> Unit,
|
||||
fabButtonClick: () -> Unit,
|
||||
@ -76,28 +79,26 @@ fun LocalLibraryScreen(
|
||||
onMultiSelect: ((BookOnDisk) -> Unit)? = null,
|
||||
navigationIcon: @Composable () -> Unit
|
||||
) {
|
||||
// val swipeRefreshState = rememberPullToRefreshState()
|
||||
KiwixTheme {
|
||||
Scaffold(
|
||||
snackbarHost = { KiwixSnackbarHost(snackbarHostState = snackBarHostState) },
|
||||
topBar = { KiwixAppBar(R.string.library, navigationIcon, actionMenuItems) },
|
||||
modifier = Modifier.systemBarsPadding()
|
||||
) { contentPadding ->
|
||||
Box(
|
||||
SwipeRefreshLayout(
|
||||
isRefreshing = swipeRefreshItem.first,
|
||||
isEnabled = swipeRefreshItem.second,
|
||||
onRefresh = onRefresh,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(contentPadding)
|
||||
// .pullToRefresh(
|
||||
// isRefreshing = swipeRefreshItem.first,
|
||||
// state = swipeRefreshState,
|
||||
// enabled = swipeRefreshItem.second,
|
||||
// onRefresh = { onRefresh }
|
||||
// )
|
||||
// .pullToRefreshIndicator(
|
||||
// state = swipeRefreshState,
|
||||
// isRefreshing = swipeRefreshItem.first
|
||||
// )
|
||||
) {
|
||||
if (scanningProgressItem.first) {
|
||||
ContentLoadingProgressBar(
|
||||
progressBarStyle = ProgressBarStyle.HORIZONTAL,
|
||||
progress = scanningProgressItem.second
|
||||
)
|
||||
}
|
||||
if (noFilesViewItem.third) {
|
||||
NoFilesView(noFilesViewItem, onDownloadButtonClick)
|
||||
} else {
|
@ -21,7 +21,7 @@ package org.kiwix.kiwixmobile.zimManager.fileselectView.effects
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.navigate
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.LocalLibraryFragmentDirections
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.local.LocalLibraryFragmentDirections
|
||||
|
||||
object NavigateToDownloads : SideEffect<Unit> {
|
||||
override fun invokeWith(activity: AppCompatActivity) {
|
||||
|
@ -25,11 +25,10 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.navigate
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
|
||||
import org.kiwix.kiwixmobile.main.KiwixMainActivity
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.LocalLibraryFragmentDirections.actionNavigationLibraryToNavigationReader
|
||||
import org.kiwix.kiwixmobile.nav.destination.library.local.LocalLibraryFragmentDirections.actionNavigationLibraryToNavigationReader
|
||||
|
||||
@Suppress("InjectDispatcher")
|
||||
data class OpenFileWithNavigation(private val bookOnDisk: BooksOnDiskListItem.BookOnDisk) :
|
||||
|
@ -65,7 +65,7 @@
|
||||
|
||||
<fragment
|
||||
android:id="@+id/libraryFragment"
|
||||
android:name="org.kiwix.kiwixmobile.nav.destination.library.LocalLibraryFragment"
|
||||
android:name="org.kiwix.kiwixmobile.nav.destination.library.local.LocalLibraryFragment"
|
||||
android:label="Library">
|
||||
<action
|
||||
android:id="@+id/action_navigation_library_to_navigation_reader"
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.core.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.ProgressIndicatorDefaults.drawStopIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.HUNDERED
|
||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.DenimBlue400
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.MineShaftGray350
|
||||
|
||||
@Composable
|
||||
fun ContentLoadingProgressBar(
|
||||
modifier: Modifier = Modifier,
|
||||
progressBarStyle: ProgressBarStyle = ProgressBarStyle.CIRCLE,
|
||||
progress: Int = ZERO,
|
||||
progressBarColor: Color = DenimBlue400,
|
||||
progressBarTrackColor: Color = MineShaftGray350
|
||||
) {
|
||||
when (progressBarStyle) {
|
||||
ProgressBarStyle.CIRCLE -> {
|
||||
CircularProgressIndicator(
|
||||
modifier = modifier,
|
||||
color = progressBarColor,
|
||||
trackColor = progressBarTrackColor
|
||||
)
|
||||
}
|
||||
|
||||
ProgressBarStyle.HORIZONTAL -> {
|
||||
LinearProgressIndicator(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
progress = { progress.toFloat() / HUNDERED },
|
||||
color = progressBarColor,
|
||||
trackColor = progressBarTrackColor,
|
||||
gapSize = ZERO.dp,
|
||||
strokeCap = StrokeCap.Butt,
|
||||
drawStopIndicator = {
|
||||
drawStopIndicator(
|
||||
drawScope = this,
|
||||
stopSize = ZERO.dp,
|
||||
color = progressBarTrackColor,
|
||||
strokeCap = StrokeCap.Butt
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class ProgressBarStyle {
|
||||
HORIZONTAL,
|
||||
CIRCLE
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.core.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults.Indicator
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshState
|
||||
import androidx.compose.material3.pulltorefresh.pullToRefresh
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.Black
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.White
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SwipeRefreshLayout(
|
||||
isRefreshing: Boolean,
|
||||
isEnabled: Boolean,
|
||||
onRefresh: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
state: PullToRefreshState = rememberPullToRefreshState(),
|
||||
contentAlignment: Alignment = Alignment.TopStart,
|
||||
indicator: @Composable BoxScope.() -> Unit = {
|
||||
Indicator(
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
isRefreshing = isRefreshing,
|
||||
state = state,
|
||||
containerColor = White,
|
||||
color = Black
|
||||
)
|
||||
},
|
||||
content: @Composable BoxScope.() -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier.pullToRefresh(
|
||||
state = state,
|
||||
isRefreshing = isRefreshing,
|
||||
onRefresh = onRefresh,
|
||||
enabled = isEnabled
|
||||
),
|
||||
contentAlignment = contentAlignment
|
||||
) {
|
||||
content()
|
||||
indicator()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user