From 9366f09292894075e10577ade4d9d7d2017d2699 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:25:12 +0530 Subject: [PATCH] feat: enhance NuvioScreenHeader with animated title transitions and dynamic header title in SearchScreen --- .../com/nuvio/app/core/ui/NuvioComponents.kt | 20 ++++++++++++++----- .../nuvio/app/features/search/SearchScreen.kt | 17 +++++++++++++++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioComponents.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioComponents.kt index 8482cb993..3bac4a830 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioComponents.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioComponents.kt @@ -1,5 +1,9 @@ package com.nuvio.app.core.ui +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -101,11 +105,17 @@ fun NuvioScreenHeader( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.Bottom, ) { - Text( - text = title, - style = MaterialTheme.typography.displayLarge, - color = MaterialTheme.colorScheme.onBackground, - ) + AnimatedContent( + targetState = title, + transitionSpec = { fadeIn() togetherWith fadeOut() }, + label = "screen_header_title", + ) { currentTitle -> + Text( + text = currentTitle, + style = MaterialTheme.typography.displayLarge, + color = MaterialTheme.colorScheme.onBackground, + ) + } Row( horizontalArrangement = Arrangement.spacedBy(2.dp), verticalAlignment = Alignment.CenterVertically, diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt index f83c6aa1b..0e4ed475f 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -55,6 +56,20 @@ fun SearchScreen( var query by rememberSaveable { mutableStateOf("") } var headerHeightPx by remember { mutableIntStateOf(0) } val listState = rememberLazyListState() + val headerTitle by remember(query, listState, headerHeightPx) { + derivedStateOf { + if (query.isNotBlank()) { + "Search" + } else { + val discoverInFocus = when { + listState.firstVisibleItemIndex > 0 -> true + headerHeightPx > 0 -> listState.firstVisibleItemScrollOffset >= (headerHeightPx * 0.65f).toInt() + else -> false + } + if (discoverInFocus) "Discover" else "Search" + } + } + } val addonRefreshKey = remember(addonsUiState.addons) { addonsUiState.addons.mapNotNull { addon -> @@ -175,7 +190,7 @@ fun SearchScreen( .padding(bottom = 12.dp) .onSizeChanged { headerHeightPx = it.height }, ) { - NuvioScreenHeader(title = "Search") + NuvioScreenHeader(title = headerTitle) Spacer(modifier = Modifier.height(12.dp)) NuvioInputField( value = query,