From 75cf97a3a45851da09f69633ee02a744174acd53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Mur=C3=A7a?= Date: Sat, 19 Jul 2025 11:02:50 -0300 Subject: [PATCH] feat: add MatchupRow and Schedule Badge to MatchDetailsScreen.kt --- .../csgomatches/ui/components/MatchCard.kt | 15 ++- .../ui/navigation/MatchDetailsRoute.kt | 4 +- .../matchdetails/MatchDetailsScreen.kt | 114 ++++++++++++++++-- .../matchdetails/MatchDetailsViewModel.kt | 27 +++++ 4 files changed, 146 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/xyz/leomurca/csgomatches/ui/components/MatchCard.kt b/app/src/main/java/xyz/leomurca/csgomatches/ui/components/MatchCard.kt index 9502337..983d6a7 100644 --- a/app/src/main/java/xyz/leomurca/csgomatches/ui/components/MatchCard.kt +++ b/app/src/main/java/xyz/leomurca/csgomatches/ui/components/MatchCard.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredWidthIn import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.shape.RoundedCornerShape @@ -25,6 +26,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage @@ -59,6 +61,7 @@ fun MatchCard( rightOpponentId = rightOpponent.id, leagueAndSerieName = leagueAndSerieName, scheduleString = scheduleConfig.first, + status = match.status ) ) }, colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface) @@ -92,7 +95,10 @@ private fun MatchupRow(leftOpponent: Opponent, rightOpponent: Opponent) { Text( leftOpponent.name, style = MaterialTheme.typography.labelMedium, - modifier = Modifier.padding(top = 10.dp) + textAlign = TextAlign.Center, + modifier = Modifier + .padding(top = 10.dp) + .requiredWidthIn(max = 60.dp) ) } @@ -115,7 +121,10 @@ private fun MatchupRow(leftOpponent: Opponent, rightOpponent: Opponent) { Text( rightOpponent.name, style = MaterialTheme.typography.labelMedium, - modifier = Modifier.padding(top = 10.dp) + textAlign = TextAlign.Center, + modifier = Modifier + .padding(top = 10.dp) + .requiredWidthIn(max = 60.dp) ) } } @@ -179,7 +188,7 @@ private fun Modifier.topBorder(color: Color, thickness: Dp): Modifier = this.the }) private fun getOrDefaultOpponents(opponents: List): Pair { - val default = Opponent(id = 0, name = "A ser definido", imageUrl = "") + val default = Opponent(id = -1, name = "A ser definido", imageUrl = "") return when { opponents.size >= 2 -> opponents[0] to opponents[1] opponents.size == 1 -> opponents[0] to default diff --git a/app/src/main/java/xyz/leomurca/csgomatches/ui/navigation/MatchDetailsRoute.kt b/app/src/main/java/xyz/leomurca/csgomatches/ui/navigation/MatchDetailsRoute.kt index 92469c6..c55db96 100644 --- a/app/src/main/java/xyz/leomurca/csgomatches/ui/navigation/MatchDetailsRoute.kt +++ b/app/src/main/java/xyz/leomurca/csgomatches/ui/navigation/MatchDetailsRoute.kt @@ -4,6 +4,7 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import androidx.navigation.toRoute import kotlinx.serialization.Serializable +import xyz.leomurca.csgomatches.domain.model.MatchStatus import xyz.leomurca.csgomatches.ui.screens.matchdetails.MatchDetailsScreen @Serializable @@ -11,7 +12,8 @@ data class MatchDetailsRoute( val leftOpponentId: Long, val rightOpponentId: Long, val leagueAndSerieName: String, - val scheduleString: String + val scheduleString: String, + val status: MatchStatus ) fun NavGraphBuilder.matchDetailsScreen(onBackClick: () -> Unit) { diff --git a/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matchdetails/MatchDetailsScreen.kt b/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matchdetails/MatchDetailsScreen.kt index 6d15551..15cba17 100644 --- a/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matchdetails/MatchDetailsScreen.kt +++ b/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matchdetails/MatchDetailsScreen.kt @@ -1,13 +1,15 @@ package xyz.leomurca.csgomatches.ui.screens.matchdetails import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredWidthIn +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Icon @@ -19,12 +21,20 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import coil3.compose.AsyncImage +import xyz.leomurca.csgomatches.R +import xyz.leomurca.csgomatches.domain.model.MatchStatus +import xyz.leomurca.csgomatches.domain.model.Team import xyz.leomurca.csgomatches.ui.components.LoadingIndicator import xyz.leomurca.csgomatches.ui.navigation.MatchDetailsRoute +import xyz.leomurca.csgomatches.ui.theme.LiveRed import xyz.leomurca.csgomatches.ui.theme.White +import xyz.leomurca.csgomatches.ui.theme.White_50 @Composable fun MatchDetailsScreen( @@ -35,15 +45,22 @@ fun MatchDetailsScreen( val uiState = viewModel.uiState.collectAsState() LaunchedEffect(Unit) { - viewModel.loadTeam(matchDetails.leftOpponentId.toString(), isLeft = true) - viewModel.loadTeam(matchDetails.rightOpponentId.toString(), isLeft = false) + if (matchDetails.leftOpponentId != -1L) { + viewModel.loadTeam(matchDetails.leftOpponentId.toString(), isLeft = true) + } else { + viewModel.updateTeamToDefault(isLeft = true) + } + if (matchDetails.rightOpponentId != -1L) { + viewModel.loadTeam(matchDetails.rightOpponentId.toString(), isLeft = false) + } else { + viewModel.updateTeamToDefault(isLeft = false) + } } - Box( + Column( modifier = Modifier .fillMaxSize() .background(MaterialTheme.colorScheme.background), - contentAlignment = Alignment.Center ) { TopBar(matchDetails.leagueAndSerieName, onBackClick) @@ -52,20 +69,97 @@ fun MatchDetailsScreen( value.errorMessage != null -> Text(value.errorMessage) value.isLoading -> LoadingIndicator() value.leftTeam != null && value.rightTeam != null -> Column { - Text(value.leftTeam.name.toString()) - Text(value.rightTeam.name.toString()) + MatchupRow(leftTeam = value.leftTeam, rightTeam = value.rightTeam) + ScheduleRow(matchDetails.scheduleString, matchDetails.status) } } } } @Composable -private fun BoxScope.TopBar(leagueAndSerieName: String, onBackClick: () -> Unit) { +fun ScheduleRow(scheduleString: String, matchStatus: MatchStatus) { + val modifier = if (matchStatus == MatchStatus.LIVE) + Modifier + .background(LiveRed, RoundedCornerShape(16.dp)) + .padding(horizontal = 12.dp, vertical = 8.dp) + else Modifier + Row( + Modifier + .fillMaxWidth() + .padding(top = 20.dp), horizontalArrangement = Arrangement.Center + ) { + Text( + scheduleString, + style = MaterialTheme.typography.headlineMedium, + color = White, + modifier = modifier + ) + } +} + +@Composable +private fun MatchupRow(leftTeam: Team, rightTeam: Team) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp, bottom = 20.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + AsyncImage( + model = leftTeam.imageUrl, + contentDescription = "${leftTeam.name} logo", + error = painterResource(R.drawable.fallback_image_round), + placeholder = painterResource(R.drawable.fallback_image_round), + modifier = Modifier.size(60.dp), + contentScale = ContentScale.Fit + ) + Text( + leftTeam.name ?: "A ser definido", + style = MaterialTheme.typography.labelMedium, + color = White, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(top = 10.dp) + .requiredWidthIn(max = 60.dp) + ) + } + Text( + "vs", + style = MaterialTheme.typography.bodyMedium, + color = White_50, + modifier = Modifier.padding(horizontal = 20.dp) + ) + + Column(horizontalAlignment = Alignment.CenterHorizontally) { + AsyncImage( + model = rightTeam.imageUrl, + contentDescription = "${rightTeam.name} logo", + error = painterResource(R.drawable.fallback_image_round), + placeholder = painterResource(R.drawable.fallback_image_round), + modifier = Modifier.size(60.dp), + contentScale = ContentScale.Fit + ) + Text( + rightTeam.name ?: "A ser definido", + style = MaterialTheme.typography.labelMedium, + color = White, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(top = 10.dp) + .requiredWidthIn(max = 60.dp) + ) + } + } +} + +@Composable +private fun TopBar(leagueAndSerieName: String, onBackClick: () -> Unit) { Row( Modifier .fillMaxWidth() .background(MaterialTheme.colorScheme.background) - .align(Alignment.TopCenter) .padding(top = 52.dp, start = 24.dp, end = 24.dp), verticalAlignment = Alignment.CenterVertically, ) { diff --git a/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matchdetails/MatchDetailsViewModel.kt b/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matchdetails/MatchDetailsViewModel.kt index 90ff857..b03aa6f 100644 --- a/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matchdetails/MatchDetailsViewModel.kt +++ b/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matchdetails/MatchDetailsViewModel.kt @@ -43,6 +43,33 @@ class MatchDetailsViewModel @Inject constructor( } } + fun updateTeamToDefault(isLeft: Boolean) { + _uiState.update { it.copy(isLoading = true, errorMessage = null) } + _uiState.update { + if (isLeft) { + it.copy( + leftTeam = Team( + id = -1, + name = null, + imageUrl = null, + players = emptyList() + ), + isLoading = false + ) + } else { + it.copy( + rightTeam = Team( + id = -1, + name = null, + imageUrl = null, + players = emptyList() + ), + isLoading = false + ) + } + } + } + data class TeamUiState( val leftTeam: Team? = null, val rightTeam: Team? = null,