From a3fdd86e01ebff24c25d792ece2b3623e61ae5c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Mur=C3=A7a?= Date: Sat, 19 Jul 2025 19:58:08 -0300 Subject: [PATCH] refactor: extract strings to string resources --- .../csgomatches/ui/components/ErrorMessage.kt | 10 +++++++-- .../csgomatches/ui/components/MatchCard.kt | 21 +++++++++++-------- .../matchdetails/MatchDetailsScreen.kt | 20 +++++++++++------- .../matchdetails/MatchDetailsViewModel.kt | 11 ++++++++-- .../ui/screens/matches/MatchesScreen.kt | 4 +++- .../leomurca/csgomatches/utils/Extensions.kt | 15 +++++++++---- app/src/main/res/values/strings.xml | 10 +++++++++ 7 files changed, 65 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/xyz/leomurca/csgomatches/ui/components/ErrorMessage.kt b/app/src/main/java/xyz/leomurca/csgomatches/ui/components/ErrorMessage.kt index c06d1ea..603ab84 100644 --- a/app/src/main/java/xyz/leomurca/csgomatches/ui/components/ErrorMessage.kt +++ b/app/src/main/java/xyz/leomurca/csgomatches/ui/components/ErrorMessage.kt @@ -19,8 +19,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import xyz.leomurca.csgomatches.R @Composable fun ErrorMessage( @@ -55,11 +57,15 @@ fun ErrorMessage( if (onRetry != null) { Spacer(modifier = Modifier.height(24.dp)) - Button(onClick = onRetry, + Button( + onClick = onRetry, colors = ButtonDefaults.buttonColors() .copy(containerColor = MaterialTheme.colorScheme.secondary) ) { - Text("Tentar novamente", style = MaterialTheme.typography.bodyMedium) + Text( + stringResource(R.string.try_again), + style = MaterialTheme.typography.bodyMedium + ) } } } 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 64516c8..98674fb 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 @@ -25,7 +25,9 @@ import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -86,7 +88,7 @@ private fun MatchupRow(leftOpponent: Opponent, rightOpponent: Opponent) { Column(horizontalAlignment = Alignment.CenterHorizontally) { AsyncImage( model = leftOpponent.imageUrl, - contentDescription = "${leftOpponent.name} logo", + contentDescription = stringResource(R.string.logo_description, leftOpponent.name), error = painterResource(R.drawable.fallback_image_round), placeholder = painterResource(R.drawable.fallback_image_round), modifier = Modifier.size(60.dp), @@ -103,7 +105,7 @@ private fun MatchupRow(leftOpponent: Opponent, rightOpponent: Opponent) { } Text( - "vs", + stringResource(R.string.versus), style = MaterialTheme.typography.bodyMedium, color = White_50, modifier = Modifier.padding(horizontal = 20.dp) @@ -112,7 +114,7 @@ private fun MatchupRow(leftOpponent: Opponent, rightOpponent: Opponent) { Column(horizontalAlignment = Alignment.CenterHorizontally) { AsyncImage( model = rightOpponent.imageUrl, - contentDescription = "${rightOpponent.name} logo", + contentDescription = stringResource(R.string.logo_description, rightOpponent.name), error = painterResource(R.drawable.fallback_image_round), placeholder = painterResource(R.drawable.fallback_image_round), modifier = Modifier.size(60.dp), @@ -141,10 +143,9 @@ private fun LeagueInfoRow(league: League, leagueAndSerieName: String) { ) { AsyncImage( model = league.imageUrl, - contentDescription = "${league.name} logo", + contentDescription = stringResource(R.string.logo_description, league.name), error = painterResource(R.drawable.fallback_image_round), placeholder = painterResource(R.drawable.fallback_image_round), - onLoading = {}, modifier = Modifier .height(16.dp) .wrapContentWidth(), @@ -187,8 +188,9 @@ private fun Modifier.topBorder(color: Color, thickness: Dp): Modifier = this.the ) }) +@Composable private fun getOrDefaultOpponents(opponents: List): Pair { - val default = Opponent(id = -1, name = "A definir", imageUrl = "") + val default = Opponent(id = -1, name = stringResource(R.string.to_be_defined), imageUrl = "") return when { opponents.size >= 2 -> opponents[0] to opponents[1] opponents.size == 1 -> opponents[0] to default @@ -196,8 +198,9 @@ private fun getOrDefaultOpponents(opponents: List): Pair "Agora" to LiveRed - MatchStatus.SCHEDULED -> beginAt.toFormattedMatchTime() to White_20 - MatchStatus.UNKNOWN -> "A definir" to White_20 + MatchStatus.LIVE -> stringResource(R.string.live) to LiveRed + MatchStatus.SCHEDULED -> beginAt.toFormattedMatchTime(LocalContext.current) to White_20 + MatchStatus.UNKNOWN -> stringResource(R.string.to_be_defined) to White_20 } 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 1c62b31..7ed4d24 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 @@ -36,6 +36,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp @@ -167,7 +168,7 @@ private fun PlayerAvatar(size: Dp, imageUrl: String?, nickName: String?) { ) { AsyncImage( model = imageUrl, - contentDescription = "$nickName logo", + contentDescription = stringResource(R.string.logo_description, nickName ?: ""), contentScale = ContentScale.Crop, onState = { isLoading = it is AsyncImagePainter.State.Loading }, modifier = Modifier.fillMaxSize() @@ -191,7 +192,7 @@ private fun PlayerInfo(player: Player, modifier: Modifier = Modifier, alignEnd: horizontalAlignment = if (alignEnd) Alignment.End else Alignment.Start ) { Text( - text = player.nickName ?: "A definir", + text = player.nickName ?: stringResource(R.string.to_be_defined), color = Color.White, style = MaterialTheme.typography.headlineLarge, maxLines = 1, @@ -239,14 +240,14 @@ private fun MatchupRow(leftTeam: Team, rightTeam: Team) { Column(horizontalAlignment = Alignment.CenterHorizontally) { AsyncImage( model = leftTeam.imageUrl, - contentDescription = "${leftTeam.name} logo", + contentDescription = stringResource(R.string.logo_description, leftTeam.name ?: ""), 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 definir", + leftTeam.name ?: stringResource(R.string.to_be_defined), style = MaterialTheme.typography.labelMedium, color = White, textAlign = TextAlign.Center, @@ -256,7 +257,7 @@ private fun MatchupRow(leftTeam: Team, rightTeam: Team) { ) } Text( - "vs", + stringResource(R.string.versus), style = MaterialTheme.typography.bodyMedium, color = White_50, modifier = Modifier.padding(horizontal = 20.dp) @@ -265,14 +266,17 @@ private fun MatchupRow(leftTeam: Team, rightTeam: Team) { Column(horizontalAlignment = Alignment.CenterHorizontally) { AsyncImage( model = rightTeam.imageUrl, - contentDescription = "${rightTeam.name} logo", + contentDescription = stringResource( + R.string.logo_description, + rightTeam.name ?: "" + ), 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 definir", + rightTeam.name ?: stringResource(R.string.to_be_defined), style = MaterialTheme.typography.labelMedium, color = White, textAlign = TextAlign.Center, @@ -300,7 +304,7 @@ private fun TopBar(leagueAndSerieName: String, onBackClick: () -> Unit) { ) { Icon( imageVector = Icons.AutoMirrored.Default.ArrowBack, - contentDescription = "Back", + contentDescription = stringResource(R.string.back), tint = White ) } 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 0ac5dfd..a355521 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 @@ -48,7 +48,10 @@ class MatchDetailsViewModel @Inject constructor( private fun teamOrWithDefaultPlayers(team: Team?): Team? { return team?.let { - val filledPlayers = it.players + List((5 - it.players.size).coerceAtLeast(0)) { playerPlaceholder() } + val filledPlayers = + it.players + List((DEFAULT_TEAM_SIZE - it.players.size).coerceAtLeast(0)) { + playerPlaceholder() + } it.copy(players = filledPlayers) } } @@ -65,7 +68,7 @@ class MatchDetailsViewModel @Inject constructor( } private fun playerPlaceholder() = Player( - id = -1, nickName = "A definir", firstName = "", lastName = "", imageUrl = null + id = -1, nickName = null, firstName = null, lastName = null, imageUrl = null ) private fun teamPlaceholder() = Team( @@ -78,4 +81,8 @@ class MatchDetailsViewModel @Inject constructor( val isLoading: Boolean = true, val errorMessage: String? = null ) + + companion object { + private const val DEFAULT_TEAM_SIZE = 5 + } } \ No newline at end of file diff --git a/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matches/MatchesScreen.kt b/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matches/MatchesScreen.kt index c18523a..6ee6527 100644 --- a/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matches/MatchesScreen.kt +++ b/app/src/main/java/xyz/leomurca/csgomatches/ui/screens/matches/MatchesScreen.kt @@ -26,8 +26,10 @@ import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import xyz.leomurca.csgomatches.R import xyz.leomurca.csgomatches.domain.model.Match import xyz.leomurca.csgomatches.ui.components.ErrorMessage import xyz.leomurca.csgomatches.ui.components.MatchCard @@ -63,7 +65,7 @@ fun MatchesScreen( TopAppBar( title = { Text( - "Partidas", + stringResource(R.string.matches), style = MaterialTheme.typography.titleLarge, color = White, modifier = Modifier.padding(top = 24.dp, start = 6.dp) diff --git a/app/src/main/java/xyz/leomurca/csgomatches/utils/Extensions.kt b/app/src/main/java/xyz/leomurca/csgomatches/utils/Extensions.kt index ee9b348..53af59f 100644 --- a/app/src/main/java/xyz/leomurca/csgomatches/utils/Extensions.kt +++ b/app/src/main/java/xyz/leomurca/csgomatches/utils/Extensions.kt @@ -1,5 +1,7 @@ package xyz.leomurca.csgomatches.utils +import android.content.Context +import xyz.leomurca.csgomatches.R import java.time.DayOfWeek import java.time.LocalDate import java.time.ZonedDateTime @@ -19,20 +21,25 @@ import java.util.Locale * @receiver the [ZonedDateTime] instance to format. If null, an empty string is returned. * @return a formatted string representing the match time, or `"A definir"` if the input is null. */ -fun ZonedDateTime?.toFormattedMatchTime(): String { - if (this == null) return "A definir" +fun ZonedDateTime?.toFormattedMatchTime(context: Context): String { + if (this == null) return context.getString(R.string.match_time_tbd) val targetDate = toLocalDate() val timeFormatter = DateTimeFormatter.ofPattern("HH:mm") return when { - targetDate.isToday() -> "Hoje, ${format(timeFormatter)}" + targetDate.isToday() -> { + val time = format(timeFormatter) + context.getString(R.string.match_time_today, time) + } + targetDate.isInCurrentWeek() -> { val dayOfWeekFormatter = DateTimeFormatter.ofPattern("EEE", Locale("pt", "BR")) val day = format(dayOfWeekFormatter).replaceFirstChar { it.titlecase(Locale("pt", "BR")) }.dropLast(1) - "$day, ${format(timeFormatter)}" + val time = format(timeFormatter) + context.getString(R.string.match_time_weekday, day, time) } else -> { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7f2759b..515cc2b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,13 @@ CSGO Matches + Partidas + vs + A definir + %1$s logo + Agora + A definir + Hoje, %1$s + %1$s, %2$s + Tentar novamente + Voltar \ No newline at end of file