Silence background refresh indicators, restyle Discover's search bar and dropdowns

Removed every "let the user know it's updating" indicator that showed
even when cached content was already on screen: Calendar's inline
header spinner, Discover's isSearching check firing before checking
for already-loaded results (same bug class as Search's fix), and
Detail's isLoading check firing before checking whether content was
already loaded. All now silently keep showing the last-known content
while a refresh is in flight, only falling back to a loading state
when there's genuinely nothing yet.

Discover's search bar and filter dropdowns still used bare Material3
defaults. Replaced the OutlinedTextField with a custom pill search bar
matching native's exact treatment (56dp pill, search glyph, borderless
BasicTextField) and gave the filter dropdowns a chevron affordance and
a themed, checkmark-style highlighted selection in the popup menu.
This commit is contained in:
KhooLy 2026-07-13 21:49:02 +03:00
parent a8627211a3
commit 05d6a1fa4f
3 changed files with 78 additions and 35 deletions

View file

@ -59,7 +59,6 @@ fun CalendarScreen(
year = state.year,
month = state.month,
language = language,
isLoading = state.isLoading,
onMonthSelected = { year, month -> onAction(CalendarAction.MonthSelected(year, month)) }
)
LazyColumn(
@ -101,7 +100,6 @@ private fun CalendarMonthHeader(
year: Int,
month: Int,
language: String?,
isLoading: Boolean,
onMonthSelected: (Int, Int) -> Unit
) {
Row(
@ -120,16 +118,11 @@ private fun CalendarMonthHeader(
}
.padding(horizontal = 16.dp, vertical = 8.dp)
)
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) {
Text(
text = localizedMonthTitle(year, month, language),
color = Color.White,
fontWeight = FontWeight.Bold
)
if (isLoading) {
CircularProgressIndicator(color = Color.White, modifier = Modifier.padding(2.dp))
}
}
Text(
text = localizedMonthTitle(year, month, language),
color = Color.White,
fontWeight = FontWeight.Bold
)
Text(
text = "",
color = Color.White,

View file

@ -37,17 +37,17 @@ fun DetailScreen(
) {
val content = state.content
when {
state.isLoading -> DetailLoading(modifier)
content == null -> DetailEmpty(
text = AppStrings.t(language, state.errorKey ?: "auto.no_results_found"),
modifier = modifier
)
else -> DetailContent(
content != null -> DetailContent(
content = content,
language = language,
onAction = onAction,
modifier = modifier
)
state.isLoading -> DetailLoading(modifier)
else -> DetailEmpty(
text = AppStrings.t(language, state.errorKey ?: "auto.no_results_found"),
modifier = modifier
)
}
}

View file

@ -7,18 +7,20 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
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.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -28,9 +30,11 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.fluxa.app.common.AppStrings
import com.fluxa.app.shared.feature.catalog.CatalogItemUiModel
import com.fluxa.app.shared.feature.catalog.CatalogRowUiModel
@ -60,19 +64,13 @@ fun DiscoverScreen(
.padding(horizontal = 20.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
OutlinedTextField(
value = searchQuery,
onValueChange = onSearchQueryChanged,
modifier = Modifier.fillMaxWidth(),
singleLine = true,
label = { Text(AppStrings.t(language, "auto.search")) }
DiscoverSearchField(
query = searchQuery,
placeholder = AppStrings.t(language, "auto.search"),
onQueryChanged = onSearchQueryChanged
)
if (searchQuery.isNotBlank()) {
when {
isSearching -> Box(
modifier = Modifier.weight(1f).fillMaxWidth(),
contentAlignment = Alignment.Center
) { CircularProgressIndicator(color = Color.White) }
searchResultRows.isNotEmpty() -> SearchResultRows(
rows = searchResultRows,
onItemSelected = onItemSelected,
@ -83,6 +81,7 @@ fun DiscoverScreen(
onItemSelected = onItemSelected,
modifier = Modifier.weight(1f)
)
isSearching -> DiscoverSkeletonGrid(modifier = Modifier.weight(1f))
else -> Box(
modifier = Modifier.weight(1f).fillMaxWidth(),
contentAlignment = Alignment.Center
@ -118,6 +117,42 @@ fun DiscoverScreen(
}
}
@Composable
private fun DiscoverSearchField(
query: String,
placeholder: String,
onQueryChanged: (String) -> Unit
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(52.dp)
.background(Color.White.copy(alpha = 0.06f), RoundedCornerShape(26.dp)),
contentAlignment = Alignment.CenterStart
) {
Row(
modifier = Modifier.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(text = "", color = Color.White.copy(alpha = 0.5f), fontSize = 18.sp)
Spacer(modifier = Modifier.width(10.dp))
Box(modifier = Modifier.fillMaxWidth()) {
if (query.isEmpty()) {
Text(text = placeholder, color = Color.White.copy(alpha = 0.4f), fontSize = 15.sp)
}
BasicTextField(
value = query,
onValueChange = onQueryChanged,
textStyle = TextStyle(color = Color.White, fontSize = 15.sp, fontWeight = FontWeight.Medium),
singleLine = true,
cursorBrush = androidx.compose.ui.graphics.SolidColor(Color.White),
modifier = Modifier.fillMaxWidth()
)
}
}
}
}
@Composable
private fun DiscoverSkeletonGrid(modifier: Modifier = Modifier) {
LazyVerticalGrid(
@ -191,24 +226,39 @@ private fun DiscoverDropdownFilter(
var expanded by remember { mutableStateOf(false) }
val selectedLabel = options.firstOrNull { it.id == selectedId }?.label ?: label
Box {
Box(
Row(
modifier = Modifier
.background(Color.White.copy(alpha = 0.12f), RoundedCornerShape(999.dp))
.background(Color.White.copy(alpha = 0.08f), RoundedCornerShape(999.dp))
.clickable { expanded = true }
.padding(horizontal = 14.dp, vertical = 8.dp)
.padding(horizontal = 14.dp, vertical = 9.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = selectedLabel,
color = Color.White,
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.width(4.dp))
Text(text = "", color = Color.White.copy(alpha = 0.6f), fontSize = 12.sp)
}
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier.background(FluxaColors.surfaceRaised, RoundedCornerShape(12.dp))
) {
options.forEach { option ->
val selected = option.id == selectedId
DropdownMenuItem(
text = { Text(option.label) },
text = {
Text(
text = option.label,
color = if (selected) FluxaColors.accent else Color.White,
fontWeight = if (selected) FontWeight.Bold else FontWeight.Normal
)
},
onClick = {
onSelected(option.id)
expanded = false