diff --git a/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageScreen.kt b/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageScreen.kt index 44393b405..99d855143 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageScreen.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageScreen.kt @@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -47,6 +48,7 @@ import org.kiwix.kiwixmobile.language.viewmodel.LanguageViewModel import org.kiwix.kiwixmobile.language.viewmodel.State import org.kiwix.kiwixmobile.language.viewmodel.State.Content +@OptIn(ExperimentalMaterial3Api::class) @SuppressLint("ComposableLambdaParameterNaming") @Composable fun LanguageScreen( @@ -68,13 +70,13 @@ fun LanguageScreen( navigationIcon = navigationIcon, actionMenuItems = actionMenuItemList, searchBar = if (isSearchActive) { - { modifier -> + { KiwixSearchView( - modifier = modifier, value = searchText, testTag = SEARCH_FIELD_TESTING_TAG, onValueChange = onAppBarValueChange, - onClearClick = onClearClick + onClearClick = onClearClick, + modifier = Modifier ) } } else { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/ContentLoadingProgressBar.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/ContentLoadingProgressBar.kt index d79d0f93f..140a6997d 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/ContentLoadingProgressBar.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/ContentLoadingProgressBar.kt @@ -42,21 +42,11 @@ fun ContentLoadingProgressBar( ) { when (progressBarStyle) { ProgressBarStyle.CIRCLE -> { - if (progress == ZERO) { - // Indeterminate mode - will spin continuously - CircularProgressIndicator( - modifier = modifier, - color = progressBarColor - ) - } else { - // Determinate mode - shows specific progress - CircularProgressIndicator( - modifier = modifier, - progress = { progress.toFloat() / HUNDERED }, - color = progressBarColor, - trackColor = progressBarTrackColor - ) - } + CircularProgressIndicator( + modifier = modifier, + color = progressBarColor, + trackColor = progressBarTrackColor + ) } ProgressBarStyle.HORIZONTAL -> { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/KiwixAppBar.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/KiwixAppBar.kt index 5ff17898d..6e7044eae 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/KiwixAppBar.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/KiwixAppBar.kt @@ -19,64 +19,86 @@ package org.kiwix.kiwixmobile.core.ui.components import androidx.annotation.StringRes -import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight.Companion.SemiBold +import androidx.compose.ui.text.style.TextOverflow +import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem -import org.kiwix.kiwixmobile.core.ui.models.IconItem +import org.kiwix.kiwixmobile.core.ui.models.toPainter import org.kiwix.kiwixmobile.core.ui.theme.Black import org.kiwix.kiwixmobile.core.ui.theme.KiwixTheme import org.kiwix.kiwixmobile.core.ui.theme.MineShaftGray350 import org.kiwix.kiwixmobile.core.ui.theme.White -import org.kiwix.kiwixmobile.core.utils.ComposeDimens.KIWIX_APP_BAR_HEIGHT import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP const val TOOLBAR_TITLE_TESTING_TAG = "toolbarTitle" +@OptIn(ExperimentalMaterial3Api::class) @Composable fun KiwixAppBar( @StringRes titleId: Int, navigationIcon: @Composable () -> Unit, actionMenuItems: List = emptyList(), + topAppBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), // Optional search bar, used in fragments that require it - searchBar: (@Composable (Modifier) -> Unit)? = null + searchBar: (@Composable () -> Unit)? = null ) { KiwixTheme { - Row( - modifier = Modifier - .fillMaxWidth() - .height(KIWIX_APP_BAR_HEIGHT) - .background(color = Black), - verticalAlignment = Alignment.CenterVertically - ) { - navigationIcon() - searchBar?.let { searchBarComposable -> - searchBarComposable( - Modifier.weight(1f) - ) - } ?: run { - // Otherwise, show the title - AppBarTitle(titleId) - Spacer(Modifier.weight(1f)) - } - ActionMenu(actionMenuItems) + TopAppBar( + title = { AppBarTitleSection(titleId, searchBar) }, + navigationIcon = navigationIcon, + actions = { ActionMenu(actionMenuItems) }, + scrollBehavior = topAppBarScrollBehavior, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Black, + scrolledContainerColor = Black + ) + ) + } +} + +@Suppress("ComposableLambdaParameterNaming") +@Composable +private fun AppBarTitleSection( + @StringRes titleId: Int, + searchBar: (@Composable () -> Unit)? = null +) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(start = SIXTEEN_DP), + contentAlignment = Alignment.CenterStart + ) { + searchBar?.let { + it() + } ?: run { + AppBarTitle(titleId) } } } @@ -93,10 +115,11 @@ private fun AppBarTitle( Text( text = stringResource(titleId), color = appBarTitleColor, - style = MaterialTheme.typography.titleLarge.copy(fontWeight = SemiBold), + style = MaterialTheme.typography.titleMedium, + overflow = TextOverflow.Ellipsis, + maxLines = 1, modifier = Modifier - .padding(horizontal = SIXTEEN_DP) - .testTag(TOOLBAR_TITLE_TESTING_TAG) + .testTag(TOOLBAR_TITLE_TESTING_TAG), ) } @@ -107,14 +130,10 @@ private fun ActionMenu(actionMenuItems: List) { IconButton( enabled = menuItem.isEnabled, onClick = menuItem.onClick, - modifier = Modifier - .testTag(menuItem.testingTag) + modifier = Modifier.testTag(menuItem.testingTag) ) { Icon( - painter = when (val icon = menuItem.icon) { - is IconItem.Vector -> rememberVectorPainter(icon.imageVector) - is IconItem.Drawable -> painterResource(icon.drawableRes) - }, + painter = menuItem.icon.toPainter(), contentDescription = stringResource(menuItem.contentDescription), tint = if (menuItem.isEnabled) menuItem.iconTint else Color.Gray ) @@ -122,3 +141,23 @@ private fun ActionMenu(actionMenuItems: List) { } } } + +@Composable +fun rememberBottomNavigationVisibility(lazyListState: LazyListState?): Boolean { + var isToolbarVisible by remember { mutableStateOf(true) } + var lastScrollIndex by remember { mutableIntStateOf(ZERO) } + val updatedLazyListState = rememberUpdatedState(lazyListState) + + LaunchedEffect(updatedLazyListState) { + updatedLazyListState.value?.let { state -> + snapshotFlow { state.firstVisibleItemIndex } + .collect { newScrollIndex -> + if (newScrollIndex != lastScrollIndex) { + isToolbarVisible = newScrollIndex < lastScrollIndex + lastScrollIndex = newScrollIndex + } + } + } + } + return isToolbarVisible +}