diff --git a/app/src/main/java/eu/gaudian/translator/view/vocabulary/CategoryDetailScreen.kt b/app/src/main/java/eu/gaudian/translator/view/vocabulary/CategoryDetailScreen.kt index bc7e8f2..49d4c53 100644 --- a/app/src/main/java/eu/gaudian/translator/view/vocabulary/CategoryDetailScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/vocabulary/CategoryDetailScreen.kt @@ -3,6 +3,7 @@ package eu.gaudian.translator.view.vocabulary import android.annotation.SuppressLint +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -12,6 +13,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults @@ -33,6 +35,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -51,7 +54,6 @@ import eu.gaudian.translator.view.composable.AppIcons import eu.gaudian.translator.view.composable.AppScaffold import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.PrimaryButton -import eu.gaudian.translator.view.composable.SecondaryButton import eu.gaudian.translator.view.dialogs.DeleteCategoryDialog import eu.gaudian.translator.view.dialogs.DeleteItemsDialog import eu.gaudian.translator.view.dialogs.EditCategoryDialog @@ -150,6 +152,24 @@ fun CategoryDetailScreen( } } + // Scroll state for animation + val listState = rememberLazyListState() + var isHeaderVisible by remember { mutableStateOf(true) } + var previousIndex by remember { mutableStateOf(0) } + var previousScrollOffset by remember { mutableStateOf(0) } + + // Detect scroll direction to show/hide header (same as LibraryScreen) + LaunchedEffect(listState) { + snapshotFlow { listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset } + .collect { (index, offset) -> + val isScrollingDown = index > previousIndex || (index == previousIndex && offset > previousScrollOffset) + val isAtTop = index == 0 && offset <= 4 + isHeaderVisible = if (isAtTop) true else !isScrollingDown + previousIndex = index + previousScrollOffset = offset + } + } + AppScaffold( modifier = modifier, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, @@ -173,7 +193,7 @@ fun CategoryDetailScreen( modifier = Modifier.width(220.dp) ) { DropdownMenuItem( - text = { + text = { Row( horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically @@ -202,6 +222,22 @@ fun CategoryDetailScreen( }, leadingIcon = { Icon(AppIcons.Delete, contentDescription = null) } ) + DropdownMenuItem( + text = { Text(stringResource(R.string.label_edit)) }, + onClick = { + categoryViewModel.setShowEditCategoryDialog(true, categoryId) + showMenu = false + }, + leadingIcon = { Icon(AppIcons.Edit, contentDescription = null) } + ) + DropdownMenuItem( + text = { Text(stringResource(R.string.label_delete)) }, + onClick = { + categoryViewModel.setShowDeleteCategoryDialog(true, categoryId) + showMenu = false + }, + leadingIcon = { Icon(AppIcons.Delete, contentDescription = null) } + ) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -209,22 +245,28 @@ fun CategoryDetailScreen( ) ) - // Category Header Card with Progress and Action Buttons - CategoryHeaderCard( - subtitle = subtitle, - categoryProgress = categoryProgress, - onStartExerciseClick = { - val categories = listOf(category) - val categoryIds = categories.joinToString(",") { it?.id.toString() } - navController.navigate("vocabulary_exercise/false?categories=$categoryIds") - }, - onEditClick = { - categoryViewModel.setShowEditCategoryDialog(true, categoryId) - }, - onDeleteClick = { - categoryViewModel.setShowDeleteCategoryDialog(true, categoryId) - } - ) + // Category Header Card with Progress and Action Buttons (animated) + androidx.compose.animation.AnimatedVisibility( + visible = isHeaderVisible, + enter = androidx.compose.animation.fadeIn() + androidx.compose.animation.expandVertically(), + exit = androidx.compose.animation.fadeOut() + androidx.compose.animation.shrinkVertically() + ) { + CategoryHeaderCard( + subtitle = subtitle, + categoryProgress = categoryProgress, + onStartExerciseClick = { + val categories = listOf(category) + val categoryIds = categories.joinToString(",") { it?.id.toString() } + navController.navigate("vocabulary_exercise/false?categories=$categoryIds") + }, + onEditClick = { + categoryViewModel.setShowEditCategoryDialog(true, categoryId) + }, + onDeleteClick = { + categoryViewModel.setShowDeleteCategoryDialog(true, categoryId) + } + ) + } } } ) { paddingValues -> @@ -236,7 +278,8 @@ fun CategoryDetailScreen( navController = navController, isRemoveFromCategoryEnabled = category is TagCategory, showTopBar = false, - enableNavigationButtons = true + enableNavigationButtons = true, + listState = listState ) // Dialogs @@ -275,12 +318,13 @@ fun CategoryHeaderCard( Card( modifier = modifier .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp), + .padding(horizontal = 16.dp, vertical = 16.dp), shape = RoundedCornerShape(20.dp), colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.3f) + containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.2f) ), - elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) + border = BorderStroke(1.dp, MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.4f)), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) ) { Column( modifier = Modifier @@ -299,22 +343,22 @@ fun CategoryHeaderCard( ) } - // Progress Circle + // Progress Circle - smaller size if (categoryProgress != null) { CategoryProgressCircle( totalItems = categoryProgress.totalItems, itemsCompleted = categoryProgress.itemsCompleted, itemsInStages = categoryProgress.itemsInStages, newItems = categoryProgress.newItems, - circleSize = 120.dp, + circleSize = 100.dp, ) - Spacer(modifier = Modifier.height(24.dp)) + Spacer(modifier = Modifier.height(20.dp)) } // Action Buttons Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(12.dp) + horizontalArrangement = Arrangement.spacedBy(16.dp) ) { // Start Exercise Button (Primary) PrimaryButton( @@ -324,30 +368,6 @@ fun CategoryHeaderCard( modifier = Modifier.weight(1f) ) } - - Spacer(modifier = Modifier.height(12.dp)) - - // Secondary Action Buttons - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - // Edit Button - SecondaryButton( - text = stringResource(R.string.label_edit), - icon = AppIcons.Edit, - onClick = onEditClick, - modifier = Modifier.weight(1f) - ) - - // Delete Button - SecondaryButton( - text = stringResource(R.string.label_delete), - icon = AppIcons.Delete, - onClick = onDeleteClick, - modifier = Modifier.weight(1f) - ) - } } } } diff --git a/app/src/main/java/eu/gaudian/translator/view/vocabulary/CategoryListScreen.kt b/app/src/main/java/eu/gaudian/translator/view/vocabulary/CategoryListScreen.kt index 23a04f8..d1d5735 100644 --- a/app/src/main/java/eu/gaudian/translator/view/vocabulary/CategoryListScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/vocabulary/CategoryListScreen.kt @@ -100,7 +100,7 @@ fun CategoryListScreen( AppScaffold( topBar = { AppTopAppBar( - title = "TODO", + title = stringResource(R.string.label_all_categories), navigationIcon = { if (isSelectionMode) { IconButton(onClick = { diff --git a/app/src/main/java/eu/gaudian/translator/view/vocabulary/VocabularyListScreen.kt b/app/src/main/java/eu/gaudian/translator/view/vocabulary/VocabularyListScreen.kt index 829d411..9c6843b 100644 --- a/app/src/main/java/eu/gaudian/translator/view/vocabulary/VocabularyListScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/vocabulary/VocabularyListScreen.kt @@ -105,11 +105,12 @@ fun AllCardsListScreen( itemsToShow: List = emptyList(), isRemoveFromCategoryEnabled: Boolean = false, showTopBar: Boolean = true, - enableNavigationButtons: Boolean = false + enableNavigationButtons: Boolean = false, + listState: androidx.compose.foundation.lazy.LazyListState = rememberLazyListState() ) { val scope = rememberCoroutineScope() val activity = LocalContext.current.findActivity() - val lazyListState = rememberLazyListState() + val lazyListState = listState val vocabularyViewModel: VocabularyViewModel = hiltViewModel(viewModelStoreOwner = activity) val exportImportViewModel: ExportImportViewModel = hiltViewModel(viewModelStoreOwner = activity) val languageViewModel: LanguageViewModel = hiltViewModel(viewModelStoreOwner = activity) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ca41bb3..2c2ff21 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1113,4 +1113,5 @@ Search Search cards learned + All Categories