mirror of
https://github.com/FluxaMedia/fluxa.git
synced 2026-08-09 00:17:35 +00:00
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:
parent
a8627211a3
commit
05d6a1fa4f
3 changed files with 78 additions and 35 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue