ui: make filter card collapsible with 2x2 grid layout
- Collapsed: compact row showing 'Filtres' + active filter count + expand arrow - Expanded: 2x2 grid (Compte+Type, Age+Sous-groupe) halves vertical space - Animated expand/collapse with AnimatedVisibility - FilterDropdown now respects weight() modifier for row layout
This commit is contained in:
@@ -28,7 +28,7 @@ fun FilterDropdown(
|
|||||||
ExposedDropdownMenuBox(
|
ExposedDropdownMenuBox(
|
||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
onExpandedChange = { expanded = it },
|
onExpandedChange = { expanded = it },
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = selectedValue ?: "",
|
value = selectedValue ?: "",
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
package ch.parano.myice.ui.screens
|
package ch.parano.myice.ui.screens
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.expandVertically
|
||||||
|
import androidx.compose.animation.shrinkVertically
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@@ -11,6 +16,7 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -20,6 +26,9 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -81,46 +90,99 @@ fun ScheduleScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize().padding(padding),
|
modifier = Modifier.fillMaxSize().padding(padding),
|
||||||
) {
|
) {
|
||||||
|
var filtersExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val activeFilterCount = listOf(
|
||||||
|
scheduleState.selectedAccount,
|
||||||
|
scheduleState.selectedAgegroup,
|
||||||
|
scheduleState.selectedSubgroup,
|
||||||
|
).count { it != null } + if (scheduleState.typeFilter != TypeFilter.GAMES) 1 else 0
|
||||||
|
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
) {
|
) {
|
||||||
Column(
|
Row(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
.fillMaxWidth()
|
||||||
|
.clickable { filtersExpanded = !filtersExpanded }
|
||||||
|
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
FilterDropdown(
|
Text(
|
||||||
label = "Compte",
|
text = "Filtres",
|
||||||
selectedValue = scheduleState.selectedAccount,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
options = scheduleState.accounts.map { it.name },
|
fontWeight = FontWeight.Medium,
|
||||||
onSelect = { it?.let { acc -> scheduleViewModel.setAccount(acc) } },
|
|
||||||
)
|
)
|
||||||
FilterDropdown(
|
if (activeFilterCount > 0) {
|
||||||
label = "Age",
|
Spacer(Modifier.height(0.dp))
|
||||||
selectedValue = scheduleState.selectedAgegroup,
|
Text(
|
||||||
options = scheduleState.agegroups,
|
text = "($activeFilterCount actif${if (activeFilterCount > 1) "s" else ""})",
|
||||||
onSelect = { scheduleViewModel.setAgegroup(it) },
|
style = MaterialTheme.typography.bodySmall,
|
||||||
)
|
color = MaterialTheme.colorScheme.primary,
|
||||||
FilterDropdown(
|
modifier = Modifier.padding(start = 8.dp),
|
||||||
label = "Sous-groupe",
|
)
|
||||||
selectedValue = scheduleState.selectedSubgroup,
|
}
|
||||||
options = scheduleState.subgroups,
|
Spacer(Modifier.weight(1f))
|
||||||
onSelect = { scheduleViewModel.setSubgroup(it) },
|
Text(
|
||||||
)
|
text = if (filtersExpanded) "▲" else "▼",
|
||||||
FilterDropdown(
|
style = MaterialTheme.typography.bodySmall,
|
||||||
label = "Type",
|
|
||||||
selectedValue = typeFilterLabel(scheduleState.typeFilter),
|
|
||||||
options = listOf("Tous", "Matchs", "Entrainements"),
|
|
||||||
onSelect = { label ->
|
|
||||||
val filter = when (label) {
|
|
||||||
"Tous" -> TypeFilter.ALL
|
|
||||||
"Matchs" -> TypeFilter.GAMES
|
|
||||||
"Entrainements" -> TypeFilter.PRACTICES
|
|
||||||
else -> TypeFilter.DEFAULT
|
|
||||||
}
|
|
||||||
scheduleViewModel.setTypeFilter(filter)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = filtersExpanded,
|
||||||
|
enter = expandVertically(),
|
||||||
|
exit = shrinkVertically(),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
FilterDropdown(
|
||||||
|
label = "Compte",
|
||||||
|
selectedValue = scheduleState.selectedAccount,
|
||||||
|
options = scheduleState.accounts.map { it.name },
|
||||||
|
onSelect = { it?.let { acc -> scheduleViewModel.setAccount(acc) } },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
)
|
||||||
|
FilterDropdown(
|
||||||
|
label = "Type",
|
||||||
|
selectedValue = typeFilterLabel(scheduleState.typeFilter),
|
||||||
|
options = listOf("Tous", "Matchs", "Entrainements"),
|
||||||
|
onSelect = { label ->
|
||||||
|
val filter = when (label) {
|
||||||
|
"Tous" -> TypeFilter.ALL
|
||||||
|
"Matchs" -> TypeFilter.GAMES
|
||||||
|
"Entrainements" -> TypeFilter.PRACTICES
|
||||||
|
else -> TypeFilter.DEFAULT
|
||||||
|
}
|
||||||
|
scheduleViewModel.setTypeFilter(filter)
|
||||||
|
},
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
FilterDropdown(
|
||||||
|
label = "Age",
|
||||||
|
selectedValue = scheduleState.selectedAgegroup,
|
||||||
|
options = scheduleState.agegroups,
|
||||||
|
onSelect = { scheduleViewModel.setAgegroup(it) },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
)
|
||||||
|
FilterDropdown(
|
||||||
|
label = "Sous-groupe",
|
||||||
|
selectedValue = scheduleState.selectedSubgroup,
|
||||||
|
options = scheduleState.subgroups,
|
||||||
|
onSelect = { scheduleViewModel.setSubgroup(it) },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
|||||||
Reference in New Issue
Block a user