refactor: extract strings to string resources
This commit is contained in:
parent
4631c7a42b
commit
a3fdd86e01
7 changed files with 65 additions and 26 deletions
|
@ -19,8 +19,10 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import xyz.leomurca.csgomatches.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ErrorMessage(
|
fun ErrorMessage(
|
||||||
|
@ -55,11 +57,15 @@ fun ErrorMessage(
|
||||||
if (onRetry != null) {
|
if (onRetry != null) {
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
Button(onClick = onRetry,
|
Button(
|
||||||
|
onClick = onRetry,
|
||||||
colors = ButtonDefaults.buttonColors()
|
colors = ButtonDefaults.buttonColors()
|
||||||
.copy(containerColor = MaterialTheme.colorScheme.secondary)
|
.copy(containerColor = MaterialTheme.colorScheme.secondary)
|
||||||
) {
|
) {
|
||||||
Text("Tentar novamente", style = MaterialTheme.typography.bodyMedium)
|
Text(
|
||||||
|
stringResource(R.string.try_again),
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,9 @@ import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
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.TextAlign
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
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) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = leftOpponent.imageUrl,
|
model = leftOpponent.imageUrl,
|
||||||
contentDescription = "${leftOpponent.name} logo",
|
contentDescription = stringResource(R.string.logo_description, leftOpponent.name),
|
||||||
error = painterResource(R.drawable.fallback_image_round),
|
error = painterResource(R.drawable.fallback_image_round),
|
||||||
placeholder = painterResource(R.drawable.fallback_image_round),
|
placeholder = painterResource(R.drawable.fallback_image_round),
|
||||||
modifier = Modifier.size(60.dp),
|
modifier = Modifier.size(60.dp),
|
||||||
|
@ -103,7 +105,7 @@ private fun MatchupRow(leftOpponent: Opponent, rightOpponent: Opponent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
"vs",
|
stringResource(R.string.versus),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = White_50,
|
color = White_50,
|
||||||
modifier = Modifier.padding(horizontal = 20.dp)
|
modifier = Modifier.padding(horizontal = 20.dp)
|
||||||
|
@ -112,7 +114,7 @@ private fun MatchupRow(leftOpponent: Opponent, rightOpponent: Opponent) {
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = rightOpponent.imageUrl,
|
model = rightOpponent.imageUrl,
|
||||||
contentDescription = "${rightOpponent.name} logo",
|
contentDescription = stringResource(R.string.logo_description, rightOpponent.name),
|
||||||
error = painterResource(R.drawable.fallback_image_round),
|
error = painterResource(R.drawable.fallback_image_round),
|
||||||
placeholder = painterResource(R.drawable.fallback_image_round),
|
placeholder = painterResource(R.drawable.fallback_image_round),
|
||||||
modifier = Modifier.size(60.dp),
|
modifier = Modifier.size(60.dp),
|
||||||
|
@ -141,10 +143,9 @@ private fun LeagueInfoRow(league: League, leagueAndSerieName: String) {
|
||||||
) {
|
) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = league.imageUrl,
|
model = league.imageUrl,
|
||||||
contentDescription = "${league.name} logo",
|
contentDescription = stringResource(R.string.logo_description, league.name),
|
||||||
error = painterResource(R.drawable.fallback_image_round),
|
error = painterResource(R.drawable.fallback_image_round),
|
||||||
placeholder = painterResource(R.drawable.fallback_image_round),
|
placeholder = painterResource(R.drawable.fallback_image_round),
|
||||||
onLoading = {},
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(16.dp)
|
.height(16.dp)
|
||||||
.wrapContentWidth(),
|
.wrapContentWidth(),
|
||||||
|
@ -187,8 +188,9 @@ private fun Modifier.topBorder(color: Color, thickness: Dp): Modifier = this.the
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@Composable
|
||||||
private fun getOrDefaultOpponents(opponents: List<Opponent>): Pair<Opponent, Opponent> {
|
private fun getOrDefaultOpponents(opponents: List<Opponent>): Pair<Opponent, Opponent> {
|
||||||
val default = Opponent(id = -1, name = "A definir", imageUrl = "")
|
val default = Opponent(id = -1, name = stringResource(R.string.to_be_defined), imageUrl = "")
|
||||||
return when {
|
return when {
|
||||||
opponents.size >= 2 -> opponents[0] to opponents[1]
|
opponents.size >= 2 -> opponents[0] to opponents[1]
|
||||||
opponents.size == 1 -> opponents[0] to default
|
opponents.size == 1 -> opponents[0] to default
|
||||||
|
@ -196,8 +198,9 @@ private fun getOrDefaultOpponents(opponents: List<Opponent>): Pair<Opponent, Opp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
private fun MatchStatus.scheduleConfigFor(beginAt: ZonedDateTime?) = when (this) {
|
private fun MatchStatus.scheduleConfigFor(beginAt: ZonedDateTime?) = when (this) {
|
||||||
MatchStatus.LIVE -> "Agora" to LiveRed
|
MatchStatus.LIVE -> stringResource(R.string.live) to LiveRed
|
||||||
MatchStatus.SCHEDULED -> beginAt.toFormattedMatchTime() to White_20
|
MatchStatus.SCHEDULED -> beginAt.toFormattedMatchTime(LocalContext.current) to White_20
|
||||||
MatchStatus.UNKNOWN -> "A definir" to White_20
|
MatchStatus.UNKNOWN -> stringResource(R.string.to_be_defined) to White_20
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.res.painterResource
|
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.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
|
@ -167,7 +168,7 @@ private fun PlayerAvatar(size: Dp, imageUrl: String?, nickName: String?) {
|
||||||
) {
|
) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = imageUrl,
|
model = imageUrl,
|
||||||
contentDescription = "$nickName logo",
|
contentDescription = stringResource(R.string.logo_description, nickName ?: ""),
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
onState = { isLoading = it is AsyncImagePainter.State.Loading },
|
onState = { isLoading = it is AsyncImagePainter.State.Loading },
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
|
@ -191,7 +192,7 @@ private fun PlayerInfo(player: Player, modifier: Modifier = Modifier, alignEnd:
|
||||||
horizontalAlignment = if (alignEnd) Alignment.End else Alignment.Start
|
horizontalAlignment = if (alignEnd) Alignment.End else Alignment.Start
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = player.nickName ?: "A definir",
|
text = player.nickName ?: stringResource(R.string.to_be_defined),
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
style = MaterialTheme.typography.headlineLarge,
|
style = MaterialTheme.typography.headlineLarge,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
|
@ -239,14 +240,14 @@ private fun MatchupRow(leftTeam: Team, rightTeam: Team) {
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = leftTeam.imageUrl,
|
model = leftTeam.imageUrl,
|
||||||
contentDescription = "${leftTeam.name} logo",
|
contentDescription = stringResource(R.string.logo_description, leftTeam.name ?: ""),
|
||||||
error = painterResource(R.drawable.fallback_image_round),
|
error = painterResource(R.drawable.fallback_image_round),
|
||||||
placeholder = painterResource(R.drawable.fallback_image_round),
|
placeholder = painterResource(R.drawable.fallback_image_round),
|
||||||
modifier = Modifier.size(60.dp),
|
modifier = Modifier.size(60.dp),
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
leftTeam.name ?: "A definir",
|
leftTeam.name ?: stringResource(R.string.to_be_defined),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
color = White,
|
color = White,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
|
@ -256,7 +257,7 @@ private fun MatchupRow(leftTeam: Team, rightTeam: Team) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
"vs",
|
stringResource(R.string.versus),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = White_50,
|
color = White_50,
|
||||||
modifier = Modifier.padding(horizontal = 20.dp)
|
modifier = Modifier.padding(horizontal = 20.dp)
|
||||||
|
@ -265,14 +266,17 @@ private fun MatchupRow(leftTeam: Team, rightTeam: Team) {
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = rightTeam.imageUrl,
|
model = rightTeam.imageUrl,
|
||||||
contentDescription = "${rightTeam.name} logo",
|
contentDescription = stringResource(
|
||||||
|
R.string.logo_description,
|
||||||
|
rightTeam.name ?: ""
|
||||||
|
),
|
||||||
error = painterResource(R.drawable.fallback_image_round),
|
error = painterResource(R.drawable.fallback_image_round),
|
||||||
placeholder = painterResource(R.drawable.fallback_image_round),
|
placeholder = painterResource(R.drawable.fallback_image_round),
|
||||||
modifier = Modifier.size(60.dp),
|
modifier = Modifier.size(60.dp),
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
rightTeam.name ?: "A definir",
|
rightTeam.name ?: stringResource(R.string.to_be_defined),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
color = White,
|
color = White,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
|
@ -300,7 +304,7 @@ private fun TopBar(leagueAndSerieName: String, onBackClick: () -> Unit) {
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.AutoMirrored.Default.ArrowBack,
|
imageVector = Icons.AutoMirrored.Default.ArrowBack,
|
||||||
contentDescription = "Back",
|
contentDescription = stringResource(R.string.back),
|
||||||
tint = White
|
tint = White
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,10 @@ class MatchDetailsViewModel @Inject constructor(
|
||||||
|
|
||||||
private fun teamOrWithDefaultPlayers(team: Team?): Team? {
|
private fun teamOrWithDefaultPlayers(team: Team?): Team? {
|
||||||
return team?.let {
|
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)
|
it.copy(players = filledPlayers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +68,7 @@ class MatchDetailsViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playerPlaceholder() = Player(
|
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(
|
private fun teamPlaceholder() = Team(
|
||||||
|
@ -78,4 +81,8 @@ class MatchDetailsViewModel @Inject constructor(
|
||||||
val isLoading: Boolean = true,
|
val isLoading: Boolean = true,
|
||||||
val errorMessage: String? = null
|
val errorMessage: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DEFAULT_TEAM_SIZE = 5
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -26,8 +26,10 @@ import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import xyz.leomurca.csgomatches.R
|
||||||
import xyz.leomurca.csgomatches.domain.model.Match
|
import xyz.leomurca.csgomatches.domain.model.Match
|
||||||
import xyz.leomurca.csgomatches.ui.components.ErrorMessage
|
import xyz.leomurca.csgomatches.ui.components.ErrorMessage
|
||||||
import xyz.leomurca.csgomatches.ui.components.MatchCard
|
import xyz.leomurca.csgomatches.ui.components.MatchCard
|
||||||
|
@ -63,7 +65,7 @@ fun MatchesScreen(
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
"Partidas",
|
stringResource(R.string.matches),
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
color = White,
|
color = White,
|
||||||
modifier = Modifier.padding(top = 24.dp, start = 6.dp)
|
modifier = Modifier.padding(top = 24.dp, start = 6.dp)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package xyz.leomurca.csgomatches.utils
|
package xyz.leomurca.csgomatches.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import xyz.leomurca.csgomatches.R
|
||||||
import java.time.DayOfWeek
|
import java.time.DayOfWeek
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.ZonedDateTime
|
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.
|
* @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.
|
* @return a formatted string representing the match time, or `"A definir"` if the input is null.
|
||||||
*/
|
*/
|
||||||
fun ZonedDateTime?.toFormattedMatchTime(): String {
|
fun ZonedDateTime?.toFormattedMatchTime(context: Context): String {
|
||||||
if (this == null) return "A definir"
|
if (this == null) return context.getString(R.string.match_time_tbd)
|
||||||
|
|
||||||
val targetDate = toLocalDate()
|
val targetDate = toLocalDate()
|
||||||
val timeFormatter = DateTimeFormatter.ofPattern("HH:mm")
|
val timeFormatter = DateTimeFormatter.ofPattern("HH:mm")
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
targetDate.isToday() -> "Hoje, ${format(timeFormatter)}"
|
targetDate.isToday() -> {
|
||||||
|
val time = format(timeFormatter)
|
||||||
|
context.getString(R.string.match_time_today, time)
|
||||||
|
}
|
||||||
|
|
||||||
targetDate.isInCurrentWeek() -> {
|
targetDate.isInCurrentWeek() -> {
|
||||||
val dayOfWeekFormatter = DateTimeFormatter.ofPattern("EEE", Locale("pt", "BR"))
|
val dayOfWeekFormatter = DateTimeFormatter.ofPattern("EEE", Locale("pt", "BR"))
|
||||||
val day = format(dayOfWeekFormatter).replaceFirstChar {
|
val day = format(dayOfWeekFormatter).replaceFirstChar {
|
||||||
it.titlecase(Locale("pt", "BR"))
|
it.titlecase(Locale("pt", "BR"))
|
||||||
}.dropLast(1)
|
}.dropLast(1)
|
||||||
"$day, ${format(timeFormatter)}"
|
val time = format(timeFormatter)
|
||||||
|
context.getString(R.string.match_time_weekday, day, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">CSGO Matches</string>
|
<string name="app_name">CSGO Matches</string>
|
||||||
|
<string name="matches">Partidas</string>
|
||||||
|
<string name="versus">vs</string>
|
||||||
|
<string name="to_be_defined">A definir</string>
|
||||||
|
<string name="logo_description">%1$s logo</string>
|
||||||
|
<string name="live">Agora</string>
|
||||||
|
<string name="match_time_tbd">A definir</string>
|
||||||
|
<string name="match_time_today">Hoje, %1$s</string>
|
||||||
|
<string name="match_time_weekday">%1$s, %2$s</string>
|
||||||
|
<string name="try_again">Tentar novamente</string>
|
||||||
|
<string name="back">Voltar</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Add table
Reference in a new issue