feat: add Material 3 theme and UI components (EventCard, FilterDropdown, LoadingIndicator)
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
package ch.parano.myice.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
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.material3.Card
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ch.parano.myice.models.Event
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun EventCard(
|
||||||
|
event: Event,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val stripeColor = event.color?.let { parseHexColor(it) }
|
||||||
|
?: MaterialTheme.colorScheme.primary
|
||||||
|
|
||||||
|
Card(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.height(120.dp),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(4.dp)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.background(stripeColor),
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.fillMaxHeight(),
|
||||||
|
verticalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(4.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${event.agegroup} - ${event.name}",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = event.title,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Adversaire: ${event.opponent}",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Lieu: ${event.place}",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "${event.start} - ${event.end}",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseHexColor(hex: String): Color {
|
||||||
|
val cleanHex = hex.removePrefix("#")
|
||||||
|
val value = cleanHex.toLong(16)
|
||||||
|
return Color(0xFF000000 or value)
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package ch.parano.myice.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||||
|
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun FilterDropdown(
|
||||||
|
label: String,
|
||||||
|
selectedValue: String?,
|
||||||
|
options: List<String>,
|
||||||
|
onSelect: (String?) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = expanded,
|
||||||
|
onExpandedChange = { expanded = it },
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = selectedValue ?: "",
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(label) },
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded) },
|
||||||
|
modifier = Modifier.menuAnchor().fillMaxWidth(),
|
||||||
|
)
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false },
|
||||||
|
) {
|
||||||
|
options.forEach { option ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(option) },
|
||||||
|
onClick = {
|
||||||
|
onSelect(option)
|
||||||
|
expanded = false
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package ch.parano.myice.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoadingIndicator(modifier: Modifier = Modifier) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package ch.parano.myice.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.darkColorScheme
|
||||||
|
import androidx.compose.material3.lightColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
private val Indigo = Color(0xFF3F51B5)
|
||||||
|
private val IndigoLight = Color(0xFF7986CB)
|
||||||
|
private val IndigoDark = Color(0xFF303F9F)
|
||||||
|
|
||||||
|
private val LightColors = lightColorScheme(
|
||||||
|
primary = Indigo,
|
||||||
|
onPrimary = Color.White,
|
||||||
|
primaryContainer = IndigoDark,
|
||||||
|
secondary = IndigoLight,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val DarkColors = darkColorScheme(
|
||||||
|
primary = IndigoLight,
|
||||||
|
onPrimary = Color.Black,
|
||||||
|
primaryContainer = Indigo,
|
||||||
|
secondary = Indigo,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MyIceTheme(
|
||||||
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
MaterialTheme(
|
||||||
|
colorScheme = if (darkTheme) DarkColors else LightColors,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user