Skip to content

Commit

Permalink
Implement multiplatform strings on Spell detail (#253)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandregpereira authored Feb 13, 2024
1 parent c89b4fe commit 0123354
Show file tree
Hide file tree
Showing 16 changed files with 297 additions and 308 deletions.
1 change: 1 addition & 0 deletions feature/spell-detail/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ java {

dependencies {
implementation project(':core:analytics')
implementation project(':core:localization')
implementation project(':domain:spell:core')
implementation project(':feature:spell-detail:event')
implementation project(':ui:core')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package br.alexandregpereira.hunter.spell.detail

import br.alexandregpereira.hunter.analytics.Analytics
import br.alexandregpereira.hunter.spell.detail.ui.SpellState

internal class SpellDetailAnalytics(
private val analytics: Analytics
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package br.alexandregpereira.hunter.spell.detail

import br.alexandregpereira.hunter.localization.AppLocalization
import br.alexandregpereira.hunter.localization.Language

interface SpellDetailStrings {
val subtitle: (Int, String) -> String
val castingTime: String
val range: String
val components: String
val duration: String
val saveType: String
val concentration: String
val atHigherLevels: String
val savingThrowStrength: String
val savingThrowDexterity: String
val savingThrowConstitution: String
val savingThrowIntelligence: String
val savingThrowWisdom: String
val savingThrowCharisma: String
val schoolAbjuration: String
val schoolConjuration: String
val schoolDivination: String
val schoolEnchantment: String
val schoolEvocation: String
val schoolIllusion: String
val schoolNecromancy: String
val schoolTransmutation: String
val cantrip: String
}

internal data class SpellDetailEnStrings(
override val subtitle: (Int, String) -> String = { level, school ->
if (level == 0) "Cantrip, $school" else "Level $level, $school"
},
override val castingTime: String = "Casting Time:",
override val range: String = "Range:",
override val components: String = "Components:",
override val duration: String = "Duration:",
override val saveType: String = "Saving Throw:",
override val concentration: String = "Concentration",
override val atHigherLevels: String = "At Higher Levels.",
override val savingThrowStrength: String = "Strength",
override val savingThrowDexterity: String = "Dexterity",
override val savingThrowConstitution: String = "Constitution",
override val savingThrowIntelligence: String = "Intelligence",
override val savingThrowWisdom: String = "Wisdom",
override val savingThrowCharisma: String = "Charisma",
override val schoolAbjuration: String = "abjuration",
override val schoolConjuration: String = "conjuration",
override val schoolDivination: String = "divination",
override val schoolEnchantment: String = "enchantment",
override val schoolEvocation: String = "evocation",
override val schoolIllusion: String = "illusion",
override val schoolNecromancy: String = "necromancy",
override val schoolTransmutation: String = "transmutation",
override val cantrip: String = "Cantrip",
) : SpellDetailStrings

internal data class SpellDetailPtStrings(
override val subtitle: (Int, String) -> String = { level, school ->
if (level == 0) "Truque, $school" else "$level° círculo, $school"
},
override val castingTime: String = "Tempo de Conjuração:",
override val range: String = "Alcance:",
override val components: String = "Componentes:",
override val duration: String = "Duração:",
override val saveType: String = "Salvaguarda:",
override val concentration: String = "Concentração",
override val atHigherLevels: String = "Em Níveis Superiores.",
override val savingThrowStrength: String = "Força",
override val savingThrowDexterity: String = "Destreza",
override val savingThrowConstitution: String = "Constituição",
override val savingThrowIntelligence: String = "Inteligência",
override val savingThrowWisdom: String = "Sabedoria",
override val savingThrowCharisma: String = "Carisma",
override val schoolAbjuration: String = "abjuração",
override val schoolConjuration: String = "conjuração",
override val schoolDivination: String = "adivinhação",
override val schoolEnchantment: String = "encantamento",
override val schoolEvocation: String = "evocação",
override val schoolIllusion: String = "ilusão",
override val schoolNecromancy: String = "necromancia",
override val schoolTransmutation: String = "transmutação",
override val cantrip: String = "Truque",
) : SpellDetailStrings

fun SpellDetailStrings(): SpellDetailStrings = SpellDetailEnStrings()

internal fun AppLocalization.getStrings(): SpellDetailStrings {
return when (getLanguage()) {
Language.ENGLISH -> SpellDetailEnStrings()
Language.PORTUGUESE -> SpellDetailPtStrings()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import br.alexandregpereira.hunter.domain.spell.GetSpellUseCase
import br.alexandregpereira.hunter.localization.AppLocalization
import br.alexandregpereira.hunter.spell.detail.event.SpellDetailEvent
import br.alexandregpereira.hunter.spell.detail.event.SpellDetailEventListener
import kotlinx.coroutines.CoroutineDispatcher
Expand All @@ -37,6 +38,7 @@ internal class SpellDetailViewModel(
private val spellDetailEventListener: SpellDetailEventListener,
private val dispatcher: CoroutineDispatcher,
private val analytics: SpellDetailAnalytics,
private val appLocalization: AppLocalization,
) : ViewModel() {

private var spellIndex: String
Expand All @@ -50,18 +52,19 @@ internal class SpellDetailViewModel(

init {
observeEvents()
if (state.value.showDetail && state.value.spell == null) {
if (state.value.showDetail && state.value.spell.index.isEmpty()) {
loadSpell(spellIndex)
}
}

private fun loadSpell(spellIndex: String) {
val strings = appLocalization.getStrings()
getSpell(spellIndex)
.map { spell -> spell.asState() }
.map { spell -> spell.asState(strings) }
.flowOn(dispatcher)
.onEach { spell ->
analytics.trackSpellLoaded(spell)
setState { changeSpell(spell) }
setState { changeSpell(spell, strings) }
}
.catch {
analytics.logException(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,27 @@
package br.alexandregpereira.hunter.spell.detail

import androidx.lifecycle.SavedStateHandle
import br.alexandregpereira.hunter.spell.detail.ui.SpellState
import br.alexandregpereira.hunter.domain.spell.model.SchoolOfMagic

internal data class SpellDetailViewState(
val spell: SpellState? = null,
val spell: SpellState = SpellState(),
val showDetail: Boolean = false,
val strings: SpellDetailStrings = SpellDetailStrings()
)

data class SpellState(
val index: String = "",
val name: String = "",
val subtitle: String = "",
val castingTime: String = "",
val components: String = "",
val duration: String = "",
val range: String = "",
val concentration: Boolean = false,
val savingThrowType: String? = null,
val school: SchoolOfMagic = SchoolOfMagic.ABJURATION,
val description: String = "",
val higherLevel: String? = null,
)

internal fun SavedStateHandle.getState(): SpellDetailViewState {
Expand All @@ -37,8 +53,11 @@ internal fun SpellDetailViewState.saveState(
return this
}

internal fun SpellDetailViewState.changeSpell(spellState: SpellState): SpellDetailViewState {
return copy(spell = spellState, showDetail = true)
internal fun SpellDetailViewState.changeSpell(
spellState: SpellState,
strings: SpellDetailStrings,
): SpellDetailViewState {
return copy(spell = spellState, showDetail = true, strings = strings)
}

internal fun SpellDetailViewState.hideDetail(): SpellDetailViewState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,52 @@

package br.alexandregpereira.hunter.spell.detail

import br.alexandregpereira.hunter.domain.spell.model.SavingThrowType
import br.alexandregpereira.hunter.domain.spell.model.SchoolOfMagic
import br.alexandregpereira.hunter.domain.spell.model.Spell
import br.alexandregpereira.hunter.spell.detail.ui.SavingThrowTypeState
import br.alexandregpereira.hunter.spell.detail.ui.SpellState
import br.alexandregpereira.hunter.ui.compose.SchoolOfMagicState

internal fun Spell.asState(): SpellState {
internal fun Spell.asState(strings: SpellDetailStrings): SpellState {
val durationText = if (concentration) {
"${strings.concentration}, ${duration.lowercase()}"
} else {
duration
}
return SpellState(
index = index,
name = name,
level = level,
subtitle = strings.subtitle(level, school.name(strings)),
castingTime = castingTime,
components = components,
duration = duration,
duration = durationText,
range = range,
ritual = ritual,
concentration = concentration,
savingThrowType = savingThrowType?.let { SavingThrowTypeState.valueOf(it.name) },
damageType = damageType,
school = SchoolOfMagicState.valueOf(school.name),
savingThrowType = savingThrowType?.name(strings),
school = school,
description = description,
higherLevel = higherLevel
)
}

private fun SchoolOfMagic.name(strings: SpellDetailStrings): String {
return when (this) {
SchoolOfMagic.ABJURATION -> strings.schoolAbjuration
SchoolOfMagic.CONJURATION -> strings.schoolConjuration
SchoolOfMagic.DIVINATION -> strings.schoolDivination
SchoolOfMagic.ENCHANTMENT -> strings.schoolEnchantment
SchoolOfMagic.EVOCATION -> strings.schoolEvocation
SchoolOfMagic.ILLUSION -> strings.schoolIllusion
SchoolOfMagic.NECROMANCY -> strings.schoolNecromancy
SchoolOfMagic.TRANSMUTATION -> strings.schoolTransmutation
}
}

private fun SavingThrowType.name(strings: SpellDetailStrings): String {
return when (this) {
SavingThrowType.STRENGTH -> strings.savingThrowStrength
SavingThrowType.DEXTERITY -> strings.savingThrowDexterity
SavingThrowType.CONSTITUTION -> strings.savingThrowConstitution
SavingThrowType.INTELLIGENCE -> strings.savingThrowIntelligence
SavingThrowType.WISDOM -> strings.savingThrowWisdom
SavingThrowType.CHARISMA -> strings.savingThrowCharisma
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ val spellDetailModule = module {
single<SpellDetailEventListener> { get<SpellDetailEventManager>() }

viewModel {
SpellDetailViewModel(get(), get(), get(), get(), analytics = SpellDetailAnalytics(get()))
SpellDetailViewModel(
savedStateHandle = get(),
getSpell = get(),
spellDetailEventListener = get(),
dispatcher = get(),
analytics = SpellDetailAnalytics(get()),
appLocalization = get(),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package br.alexandregpereira.hunter.spell.detail.ui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.compositionLocalOf
import br.alexandregpereira.hunter.spell.detail.SpellDetailStrings

internal val LocalStrings = compositionLocalOf { SpellDetailStrings() }

internal val strings: SpellDetailStrings
@Composable
get() = LocalStrings.current
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
Expand All @@ -30,14 +29,13 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import br.alexandregpereira.hunter.spell.detail.R
import br.alexandregpereira.hunter.ui.compose.Window

@Composable
fun SpellDescription(
internal fun SpellDescription(
description: String,
higherLevel: String? = null,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
higherLevel: String? = null
) = Column(modifier) {
Text(
text = description,
Expand All @@ -54,7 +52,7 @@ fun SpellDescription(
fontStyle = FontStyle.Italic,
)
) {
append("${stringResource(R.string.spell_detail_higher_level)} ")
append("${strings.atHigherLevels} ")
}

withStyle(
Expand Down
Loading

0 comments on commit 0123354

Please sign in to comment.