Skip to content

Commit

Permalink
Add monster XP on detail screen (#231)
Browse files Browse the repository at this point in the history
* Add monster XP on detail screen

* Fix xp formatting
  • Loading branch information
alexandregpereira authored Jan 14, 2024
1 parent c0be744 commit bd265bc
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import br.alexandregpereira.hunter.domain.monster.spell.model.SpellPreview
import br.alexandregpereira.hunter.domain.monster.spell.model.SpellUsage
import br.alexandregpereira.hunter.domain.monster.spell.model.Spellcasting
import br.alexandregpereira.hunter.domain.monster.spell.model.SpellcastingType
import java.text.NumberFormat
import kotlin.native.ObjCName

@ObjCName(name = "Monster", exact = true)
Expand Down Expand Up @@ -53,8 +54,11 @@ data class Monster(
val reactions: List<AbilityDescription> = emptyList(),
val spellcastings: List<Spellcasting> = emptyList(),
val lore: String? = null,
val isClone: Boolean = false
)
val isClone: Boolean = false,
) {

val xp: Int = challengeRatingToXp()
}

data class MonsterImageData(
val url: String = "",
Expand All @@ -69,6 +73,59 @@ data class Color(

fun Monster.isComplete() = abilityScores.isNotEmpty()

private fun Monster.challengeRatingToXp(): Int {
return when (challengeRating) {
0.125f -> 25
0.25f -> 50
0.5f -> 100
1f -> 200
2f -> 450
3f -> 700
4f -> 1100
5f -> 1800
6f -> 2300
7f -> 2900
8f -> 3900
9f -> 5000
10f -> 5900
11f -> 7200
12f -> 8400
13f -> 10000
14f -> 11500
15f -> 13000
16f -> 15000
17f -> 18000
18f -> 20000
19f -> 22000
20f -> 25000
21f -> 33000
22f -> 41000
23f -> 50000
24f -> 62000
25f -> 75000
26f -> 90000
27f -> 105000
28f -> 120000
29f -> 135000
30f -> 155000
else -> 10
}
}

fun Monster.xpFormatted(): String {
val xpString = when {
xp < 1000 -> xp.toString()
else -> {
val xpFormatted = NumberFormat.getIntegerInstance().format(xp)
.dropLastWhile { it == '0' }
.let { if (it.last().isDigit().not()) it.dropLast(1) else it }
"${xpFormatted}k"
}
}

return "$xpString XP"
}

fun getFakeMonster(): Monster {
return Monster(
index = "1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ import br.alexandregpereira.hunter.domain.model.MonsterType
import br.alexandregpereira.hunter.domain.model.SavingThrow
import br.alexandregpereira.hunter.domain.model.Skill
import br.alexandregpereira.hunter.domain.model.SpeedValue
import br.alexandregpereira.hunter.domain.model.xpFormatted
import br.alexandregpereira.hunter.domain.monster.spell.model.Spellcasting
import br.alexandregpereira.hunter.ui.compose.SchoolOfMagicState
import java.text.NumberFormat

internal fun List<Monster>.asState(): List<MonsterState> {
return this.map { it.asState() }
Expand All @@ -61,7 +63,12 @@ private fun Monster.asState(): MonsterState {
return MonsterState(
index = index,
name = name,
imageState = imageData.asState(type, challengeRating, contentDescription = name),
imageState = imageData.asState(
type = type,
challengeRating = challengeRating,
xp = xpFormatted(),
contentDescription = name
),
subtype = subtype,
group = group,
subtitle = subtitle,
Expand Down Expand Up @@ -101,6 +108,7 @@ private fun Monster.asState(): MonsterState {
private fun MonsterImageData.asState(
type: MonsterType,
challengeRating: Float,
xp: String,
contentDescription: String,
): MonsterImageState {
return MonsterImageState(
Expand All @@ -111,6 +119,7 @@ private fun MonsterImageData.asState(
dark = backgroundColor.dark,
),
challengeRating = challengeRating,
xp = xp,
isHorizontal = isHorizontal,
contentDescription = contentDescription,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,10 @@ private fun ChallengeRatingCompose(
AlphaTransition(dataList = monsters, pagerState, modifier = modifier) { data: MonsterState ->
ChallengeRatingCircle(
challengeRating = data.imageState.challengeRating,
size = 56.dp,
fontSize = 16.sp,
xp = data.imageState.xp,
size = 62.dp,
fontSize = 18.sp,
xpFontSize = 12.sp,
contentTopPadding = contentTopPadding
)
}
Expand Down Expand Up @@ -410,6 +412,7 @@ private fun MonsterDetailPreview() = Window {
url = "",
type = MonsterTypeState.CELESTIAL,
challengeRating = 0.0f,
xp = "100 XP",
backgroundColor = ColorState(
light = "#ffe2e2",
dark = "#ffe2e2"
Expand Down Expand Up @@ -459,6 +462,7 @@ private fun MonsterTopBarPreview() = Window {
url = "",
type = MonsterTypeState.CELESTIAL,
challengeRating = 0.0f,
xp = "100 XP",
backgroundColor = ColorState(
light = "#ffe2e2",
dark = "#ffe2e2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ data class MonsterState(
dark = ""
),
challengeRating = 0.0f,
xp = "",
isHorizontal = false,
contentDescription = ""
),
Expand Down Expand Up @@ -175,6 +176,7 @@ data class MonsterImageState(
val type: MonsterTypeState,
val backgroundColor: ColorState,
val challengeRating: Float,
val xp: String,
val isHorizontal: Boolean = false,
val contentDescription: String = ""
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@
package br.alexandregpereira.hunter.ui.compose

import androidx.compose.foundation.Canvas
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.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
Expand All @@ -42,33 +48,59 @@ fun ChallengeRatingCircle(
challengeRating: Float,
size: Dp,
modifier: Modifier = Modifier,
fontSize: TextUnit = 14.sp,
contentTopPadding: Dp = 0.dp
xp: String = "",
fontSize: TextUnit = 16.sp,
contentTopPadding: Dp = 0.dp,
xpFontSize: TextUnit = 10.sp,
) = Box(
contentAlignment = Alignment.CenterStart,
modifier = modifier
.width(size)
.widthIn(min = size)
.height(size + contentTopPadding)
) {
DrawChallengeRatingCircle(
color = MaterialTheme.colors.surface,
canvasSize = size,
contentTopPadding = contentTopPadding
)
Text(
challengeRating.getChallengeRatingFormatted(),
fontWeight = FontWeight.SemiBold,
fontSize = fontSize,
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
maxLines = 1,
modifier = Modifier
.width(size - 16.dp)
.padding(
bottom = 16.dp,
top = contentTopPadding + 4.dp
Column(
modifier = Modifier.background(
color = MaterialTheme.colors.surface,
shape = RoundedCornerShape(bottomEndPercent = 25)
)
) {
Spacer(modifier = Modifier.height(4.dp))

Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(vertical = 4.dp)
.padding(top = contentTopPadding)
) {
Text(
challengeRating.getChallengeRatingFormatted(),
fontWeight = FontWeight.SemiBold,
fontSize = fontSize,
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
maxLines = 1,
modifier = Modifier
.width(size - 16.dp)
)
)

if (xp.isNotBlank()) {
Text(
xp,
fontWeight = FontWeight.Normal,
fontSize = xpFontSize,
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
maxLines = 1,
modifier = Modifier
.padding(start = 4.dp, end = 8.dp)
)
}
}
}
}

@Composable
Expand Down Expand Up @@ -110,13 +142,39 @@ private fun Float.getChallengeRatingFormatted(): String {
}
}

@Preview
@Composable
private fun ChallengeRatingWithXpPreview() {
HunterTheme {
ChallengeRatingCircle(
challengeRating = 10f,
xp = "111k XP",
size = 62.dp,
fontSize = 18.sp,
xpFontSize = 14.sp,
)
}
}

@Preview
@Composable
private fun ChallengeRatingWithXpPreviewWithDifferentSize() {
HunterTheme {
ChallengeRatingCircle(
challengeRating = 10f,
xp = "155k XP",
size = 56.dp,
fontSize = 16.sp,
contentTopPadding = 24.dp
)
}
}

@Preview
@Composable
private fun ChallengeRatingPreview() {
HunterTheme {
ChallengeRatingCircle(10f, 48.dp)
ChallengeRatingCircle(challengeRating = 10f, size = 48.dp)
}
}

Expand All @@ -125,7 +183,7 @@ private fun ChallengeRatingPreview() {
private fun ChallengeRatingPreviewWithDifferentSize() {
HunterTheme {
ChallengeRatingCircle(
10f,
challengeRating = 10f,
size = 56.dp,
fontSize = 16.sp,
contentTopPadding = 24.dp
Expand Down

0 comments on commit bd265bc

Please sign in to comment.