Add a specific tab for description.
This commit is contained in:
parent
d8f79b92f9
commit
6528b89f6b
23 changed files with 242 additions and 138 deletions
|
|
@ -5,9 +5,11 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.pixelized.rplexicon.model.Description
|
||||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||||
|
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||||
import com.pixelized.rplexicon.repository.data.LexiconRepository
|
import com.pixelized.rplexicon.repository.data.LexiconRepository
|
||||||
import com.pixelized.rplexicon.repository.data.LocationRepository
|
import com.pixelized.rplexicon.repository.data.LocationRepository
|
||||||
import com.pixelized.rplexicon.repository.data.QuestRepository
|
import com.pixelized.rplexicon.repository.data.QuestRepository
|
||||||
|
|
@ -29,6 +31,7 @@ class LauncherViewModel @Inject constructor(
|
||||||
characterSheetRepository: CharacterSheetRepository,
|
characterSheetRepository: CharacterSheetRepository,
|
||||||
actionRepository: ActionRepository,
|
actionRepository: ActionRepository,
|
||||||
spellRepository: SpellRepository,
|
spellRepository: SpellRepository,
|
||||||
|
descriptionRepository: DescriptionRepository,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _error = MutableSharedFlow<String>()
|
private val _error = MutableSharedFlow<String>()
|
||||||
|
|
@ -67,7 +70,14 @@ class LauncherViewModel @Inject constructor(
|
||||||
_error.tryEmit("CharacterSheet fail to update")
|
_error.tryEmit("CharacterSheet fail to update")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
awaitAll(lexicon, location, quest, characterSheet)
|
val descriptionSheet = async {
|
||||||
|
try {
|
||||||
|
descriptionRepository.fetchDescription()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
_error.tryEmit("Skill/Spell description fail to update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitAll(lexicon, location, quest, characterSheet, descriptionSheet)
|
||||||
|
|
||||||
val alteration = async {
|
val alteration = async {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ data class Alteration(
|
||||||
val source: String,
|
val source: String,
|
||||||
val target: String,
|
val target: String,
|
||||||
val active: Boolean = false,
|
val active: Boolean = false,
|
||||||
val description: String,
|
|
||||||
val status: Map<Property, Status>,
|
val status: Map<Property, Status>,
|
||||||
) {
|
) {
|
||||||
data class Status(
|
data class Status(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package com.pixelized.rplexicon.model
|
|
||||||
|
|
||||||
data class Counter(
|
|
||||||
val title: String? = null,
|
|
||||||
val value: Int,
|
|
||||||
val max: Int?,
|
|
||||||
)
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.pixelized.rplexicon.model
|
||||||
|
|
||||||
|
data class Description(
|
||||||
|
val name: String,
|
||||||
|
val original: String,
|
||||||
|
val description: String,
|
||||||
|
)
|
||||||
|
|
@ -9,7 +9,6 @@ data class Spell(
|
||||||
val range: String,
|
val range: String,
|
||||||
val requirement: String,
|
val requirement: String,
|
||||||
val duration: String,
|
val duration: String,
|
||||||
val description: String,
|
|
||||||
val ritual: Boolean,
|
val ritual: Boolean,
|
||||||
) {
|
) {
|
||||||
enum class School(val key: String) {
|
enum class School(val key: String) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.pixelized.rplexicon.repository.data
|
||||||
|
|
||||||
|
import com.pixelized.rplexicon.model.Description
|
||||||
|
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||||
|
import com.pixelized.rplexicon.repository.parser.DescriptionParser
|
||||||
|
import com.pixelized.rplexicon.utilitary.Update
|
||||||
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class DescriptionRepository @Inject constructor(
|
||||||
|
private val googleRepository: GoogleSheetServiceRepository,
|
||||||
|
private val parser: DescriptionParser,
|
||||||
|
) {
|
||||||
|
private val _data = MutableStateFlow<Map<String, Description>>(emptyMap())
|
||||||
|
val data: StateFlow<Map<String, Description>> get() = _data
|
||||||
|
|
||||||
|
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun find(name: String?): Description? = _data.value[name]
|
||||||
|
|
||||||
|
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||||
|
suspend fun fetchDescription() {
|
||||||
|
googleRepository.fetch { sheet ->
|
||||||
|
val request = sheet.get(Sheet.Character.ID, Sheet.Character.DESCRIPTION)
|
||||||
|
val data = parser.parse(data = request.execute())
|
||||||
|
_data.tryEmit(data)
|
||||||
|
|
||||||
|
lastSuccessFullUpdate = Update.currentTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.pixelized.rplexicon.repository.data
|
package com.pixelized.rplexicon.repository.data
|
||||||
|
|
||||||
|
import com.pixelized.rplexicon.model.Description
|
||||||
|
|
||||||
object Sheet {
|
object Sheet {
|
||||||
object Lexicon {
|
object Lexicon {
|
||||||
const val ID = "1oL9Nu5y37BPEbKxHre4TN9o8nrgy2JQoON4RRkdAHMs"
|
const val ID = "1oL9Nu5y37BPEbKxHre4TN9o8nrgy2JQoON4RRkdAHMs"
|
||||||
|
|
@ -17,7 +19,7 @@ object Sheet {
|
||||||
const val ATTACK = "Attaques"
|
const val ATTACK = "Attaques"
|
||||||
const val MAGIC = "Magies"
|
const val MAGIC = "Magies"
|
||||||
const val MAGIC_LEXICON = "Lexique magique"
|
const val MAGIC_LEXICON = "Lexique magique"
|
||||||
const val STATUS = "État des personnages"
|
|
||||||
const val ALTERATION = "Altérations"
|
const val ALTERATION = "Altérations"
|
||||||
|
const val DESCRIPTION = "Descriptions"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.pixelized.rplexicon.repository.parser
|
||||||
|
|
||||||
|
import com.google.api.services.sheets.v4.model.ValueRange
|
||||||
|
import com.pixelized.rplexicon.model.Description
|
||||||
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
|
import com.pixelized.rplexicon.utilitary.extentions.local.checkSheetStructure
|
||||||
|
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DescriptionParser @Inject constructor() {
|
||||||
|
|
||||||
|
@Throws(IncompatibleSheetStructure::class)
|
||||||
|
fun parse(data: ValueRange): Map<String, Description> {
|
||||||
|
val sheet = data.values.sheet()
|
||||||
|
val values = hashMapOf<String, Description>()
|
||||||
|
|
||||||
|
lateinit var structure: Map<String, Int>
|
||||||
|
|
||||||
|
sheet?.forEachIndexed { index, item ->
|
||||||
|
when {
|
||||||
|
index == 0 -> {
|
||||||
|
structure = item.checkSheetStructure(model = COLUMNS)
|
||||||
|
}
|
||||||
|
|
||||||
|
item is List<*> -> {
|
||||||
|
val name = item[structure.getValue(NAME)] as? String
|
||||||
|
val translate = item[structure.getValue(TRANSLATE)] as? String
|
||||||
|
val description = item[structure.getValue(DESCRIPTION)] as? String
|
||||||
|
|
||||||
|
if (name != null && translate != null && description != null) {
|
||||||
|
values[name] = Description(
|
||||||
|
name = name,
|
||||||
|
original = translate,
|
||||||
|
description = description,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val NAME = "Nom"
|
||||||
|
private const val TRANSLATE = "Traduction"
|
||||||
|
private const val DESCRIPTION = "Description"
|
||||||
|
|
||||||
|
private val COLUMNS = listOf(
|
||||||
|
NAME,
|
||||||
|
TRANSLATE,
|
||||||
|
DESCRIPTION,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -46,7 +46,6 @@ class AlterationParser @Inject constructor(
|
||||||
source = source,
|
source = source,
|
||||||
target = target,
|
target = target,
|
||||||
active = false,
|
active = false,
|
||||||
description = row.parseString(DESCRIPTION) ?: "",
|
|
||||||
status = properties
|
status = properties
|
||||||
.mapNotNull { property ->
|
.mapNotNull { property ->
|
||||||
val column = alterationStructure.getValue(property.key)
|
val column = alterationStructure.getValue(property.key)
|
||||||
|
|
@ -128,8 +127,7 @@ class AlterationParser @Inject constructor(
|
||||||
|
|
||||||
private const val TARGET = "Cible"
|
private const val TARGET = "Cible"
|
||||||
private const val SOURCE = "Source"
|
private const val SOURCE = "Source"
|
||||||
private const val DESCRIPTION = "Description"
|
|
||||||
private val COLUMNS
|
private val COLUMNS
|
||||||
get() = listOf(SOURCE, TARGET, DESCRIPTION) + Property.values().map { it.key }
|
get() = listOf(SOURCE, TARGET) + Property.values().map { it.key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
package com.pixelized.rplexicon.repository.parser.alteration
|
|
||||||
|
|
||||||
import com.google.api.services.sheets.v4.model.ValueRange
|
|
||||||
import com.pixelized.rplexicon.model.Counter
|
|
||||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class CounterParser @Inject constructor() {
|
|
||||||
|
|
||||||
@Throws(IncompatibleSheetStructure::class)
|
|
||||||
fun parse(values: ValueRange): Map<String, List<Counter>> {
|
|
||||||
val sheet = values.values.sheet()
|
|
||||||
lateinit var characters: List<String>
|
|
||||||
val counters = hashMapOf<String, MutableList<Counter>>()
|
|
||||||
|
|
||||||
sheet?.mapNotNull { it as? List<*> }?.forEachIndexed { columnIndex, row ->
|
|
||||||
when (columnIndex) {
|
|
||||||
0 -> characters = row
|
|
||||||
.subList(fromIndex = 1, toIndex = row.size)
|
|
||||||
.map { it.toString() }
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
row.getOrNull(0)?.toString()?.let { title ->
|
|
||||||
row.subList(fromIndex = 1, toIndex = row.size)
|
|
||||||
.forEachIndexed { rowIndex, value ->
|
|
||||||
val counter = parseCounter(title = title, value = value?.toString())
|
|
||||||
if (counter != null) {
|
|
||||||
counters
|
|
||||||
.getOrPut(characters[rowIndex]) { mutableListOf() }
|
|
||||||
.add(counter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return counters
|
|
||||||
}
|
|
||||||
|
|
||||||
fun parseCounter(title: String? = null, value: String?): Counter? {
|
|
||||||
return if (value != null) {
|
|
||||||
COUNTER_REGEX.find(value)?.let {
|
|
||||||
val (actual, max) = it.destructured
|
|
||||||
Counter(
|
|
||||||
title = title,
|
|
||||||
value = actual.toIntOrNull() ?: 0,
|
|
||||||
max = max.toIntOrNull(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val COUNTER_REGEX = Regex("(\\d+)\\/(\\d+)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -37,7 +37,6 @@ class SpellBookParser @Inject constructor() {
|
||||||
val range = row.parse(RANGE)
|
val range = row.parse(RANGE)
|
||||||
val requirement = row.parse(REQUIREMENT)
|
val requirement = row.parse(REQUIREMENT)
|
||||||
val duration = row.parse(DURATION)
|
val duration = row.parse(DURATION)
|
||||||
val description = row.parse(DESCRIPTION)
|
|
||||||
val ritual = row.parse(RITUAL)?.toBoolean() ?: false
|
val ritual = row.parse(RITUAL)?.toBoolean() ?: false
|
||||||
if (name != null
|
if (name != null
|
||||||
&& level != null
|
&& level != null
|
||||||
|
|
@ -47,7 +46,6 @@ class SpellBookParser @Inject constructor() {
|
||||||
&& range != null
|
&& range != null
|
||||||
&& requirement != null
|
&& requirement != null
|
||||||
&& duration != null
|
&& duration != null
|
||||||
&& description != null
|
|
||||||
) {
|
) {
|
||||||
Spell(
|
Spell(
|
||||||
name = name,
|
name = name,
|
||||||
|
|
@ -58,7 +56,6 @@ class SpellBookParser @Inject constructor() {
|
||||||
range = range,
|
range = range,
|
||||||
requirement = requirement,
|
requirement = requirement,
|
||||||
duration = duration,
|
duration = duration,
|
||||||
description = description,
|
|
||||||
ritual = ritual,
|
ritual = ritual,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -88,7 +85,6 @@ class SpellBookParser @Inject constructor() {
|
||||||
private const val REQUIREMENT = "Composantes"
|
private const val REQUIREMENT = "Composantes"
|
||||||
private const val DURATION = "Durée"
|
private const val DURATION = "Durée"
|
||||||
private const val RITUAL = "Rituel"
|
private const val RITUAL = "Rituel"
|
||||||
private const val DESCRIPTION = "Description"
|
|
||||||
|
|
||||||
private val COLUMNS
|
private val COLUMNS
|
||||||
get() = listOf(
|
get() = listOf(
|
||||||
|
|
@ -101,7 +97,6 @@ class SpellBookParser @Inject constructor() {
|
||||||
REQUIREMENT,
|
REQUIREMENT,
|
||||||
DURATION,
|
DURATION,
|
||||||
RITUAL,
|
RITUAL,
|
||||||
DESCRIPTION,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import com.pixelized.rplexicon.LocalSnack
|
import com.pixelized.rplexicon.LocalSnack
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
sealed class FetchErrorUio {
|
sealed class FetchErrorUio {
|
||||||
|
|
@ -25,7 +25,7 @@ sealed class FetchErrorUio {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HandleFetchError(
|
fun HandleFetchError(
|
||||||
errors: SharedFlow<FetchErrorUio>,
|
errors: Flow<FetchErrorUio>,
|
||||||
onStructureError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Structure) -> Unit = { context, snack, _ ->
|
onStructureError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Structure) -> Unit = { context, snack, _ ->
|
||||||
snack.showSnackbar(message = context.getString(R.string.error_structure))
|
snack.showSnackbar(message = context.getString(R.string.error_structure))
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.BoxScope
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
|
@ -42,7 +41,6 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
|
@ -53,7 +51,6 @@ import com.pixelized.rplexicon.LocalSnack
|
||||||
import com.pixelized.rplexicon.NO_WINDOW_INSETS
|
import com.pixelized.rplexicon.NO_WINDOW_INSETS
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.ui.composable.IndicatorStep
|
import com.pixelized.rplexicon.ui.composable.IndicatorStep
|
||||||
import com.pixelized.rplexicon.ui.composable.IndicatorStepPreview
|
|
||||||
import com.pixelized.rplexicon.ui.composable.Loader
|
import com.pixelized.rplexicon.ui.composable.Loader
|
||||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.ProficiencyUio.ID.*
|
import com.pixelized.rplexicon.ui.screens.character.composable.character.ProficiencyUio.ID.*
|
||||||
|
|
@ -112,6 +109,7 @@ fun CharacterSheetScreen(
|
||||||
pagerState = pagerState,
|
pagerState = pagerState,
|
||||||
sheetState = sheetState,
|
sheetState = sheetState,
|
||||||
refreshState = refresh,
|
refreshState = refresh,
|
||||||
|
name = viewModel.character,
|
||||||
onRefresh = {
|
onRefresh = {
|
||||||
scope.launch { viewModel.update(force = true) }
|
scope.launch { viewModel.update(force = true) }
|
||||||
},
|
},
|
||||||
|
|
@ -120,6 +118,9 @@ fun CharacterSheetScreen(
|
||||||
},
|
},
|
||||||
indicator = {
|
indicator = {
|
||||||
IndicatorStep(
|
IndicatorStep(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(alignment = Alignment.BottomCenter)
|
||||||
|
.padding(all = 4.dp),
|
||||||
count = pagerState.pageCount,
|
count = pagerState.pageCount,
|
||||||
selectedIndex = pagerState.currentPage,
|
selectedIndex = pagerState.currentPage,
|
||||||
)
|
)
|
||||||
|
|
@ -191,12 +192,13 @@ private fun CharacterSheetContent(
|
||||||
sheetState: ModalBottomSheetState,
|
sheetState: ModalBottomSheetState,
|
||||||
refreshState: PullRefreshState,
|
refreshState: PullRefreshState,
|
||||||
onRefresh: () -> Unit,
|
onRefresh: () -> Unit,
|
||||||
|
name: String,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
loader: @Composable BoxScope.() -> Unit,
|
loader: @Composable BoxScope.() -> Unit,
|
||||||
proficiencies: @Composable PagerScope.() -> Unit,
|
proficiencies: @Composable PagerScope.() -> Unit,
|
||||||
actions: @Composable PagerScope.() -> Unit,
|
actions: @Composable PagerScope.() -> Unit,
|
||||||
alterations: @Composable PagerScope.() -> Unit,
|
alterations: @Composable PagerScope.() -> Unit,
|
||||||
indicator: @Composable ColumnScope.() -> Unit,
|
indicator: @Composable BoxScope.() -> Unit,
|
||||||
sheet: @Composable () -> Unit,
|
sheet: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
|
@ -223,9 +225,7 @@ private fun CharacterSheetContent(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(text = name)
|
||||||
text = stringResource(id = R.string.character_sheet_title),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -266,8 +266,8 @@ private fun CharacterSheetContent(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
loader()
|
loader()
|
||||||
|
indicator()
|
||||||
}
|
}
|
||||||
indicator()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -296,13 +296,22 @@ private fun CharacterScreenPreview(
|
||||||
sheetState = sheetState,
|
sheetState = sheetState,
|
||||||
pagerState = rememberPagerState(initialPage = preview) { 2 },
|
pagerState = rememberPagerState(initialPage = preview) { 2 },
|
||||||
refreshState = rememberPullRefreshState(refreshing = false, onRefresh = { }),
|
refreshState = rememberPullRefreshState(refreshing = false, onRefresh = { }),
|
||||||
onRefresh = { },
|
name = "Brulkhai",
|
||||||
onBack = { },
|
onBack = { },
|
||||||
|
onRefresh = { },
|
||||||
loader = { },
|
loader = { },
|
||||||
proficiencies = { ProficiencyPreview() },
|
proficiencies = { ProficiencyPreview() },
|
||||||
actions = { ActionPagePreview() },
|
actions = { ActionPagePreview() },
|
||||||
alterations = { AlterationPagePreview() },
|
alterations = { AlterationPagePreview() },
|
||||||
indicator = { IndicatorStepPreview() },
|
indicator = {
|
||||||
|
IndicatorStep(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(alignment = Alignment.BottomCenter)
|
||||||
|
.padding(all = 4.dp),
|
||||||
|
count = 3,
|
||||||
|
selectedIndex = 0,
|
||||||
|
)
|
||||||
|
},
|
||||||
sheet = { SpellLevelChooserPreview() },
|
sheet = { SpellLevelChooserPreview() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.pixelized.rplexicon.ui.screens.character
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.pixelized.rplexicon.repository.authentication.FirebaseRepository
|
import com.pixelized.rplexicon.repository.authentication.FirebaseRepository
|
||||||
|
|
@ -11,6 +12,7 @@ import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||||
|
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
|
@ -27,6 +29,7 @@ class CharacterSheetViewModel @Inject constructor(
|
||||||
private val actionRepository: ActionRepository,
|
private val actionRepository: ActionRepository,
|
||||||
private val spellRepository: SpellRepository,
|
private val spellRepository: SpellRepository,
|
||||||
private val firebaseRepository: FirebaseRepository,
|
private val firebaseRepository: FirebaseRepository,
|
||||||
|
savedStateHandle: SavedStateHandle,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _isLoading = mutableStateOf(false)
|
private val _isLoading = mutableStateOf(false)
|
||||||
val isLoading: State<Boolean> get() = _isLoading
|
val isLoading: State<Boolean> get() = _isLoading
|
||||||
|
|
@ -34,6 +37,8 @@ class CharacterSheetViewModel @Inject constructor(
|
||||||
private val _error = MutableSharedFlow<FetchErrorUio.Firebase>()
|
private val _error = MutableSharedFlow<FetchErrorUio.Firebase>()
|
||||||
val errors: SharedFlow<FetchErrorUio.Firebase> get() = _error
|
val errors: SharedFlow<FetchErrorUio.Firebase> get() = _error
|
||||||
|
|
||||||
|
val character = savedStateHandle.characterSheetArgument.name
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
launch {
|
launch {
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ fun ActionsPageContent(
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
contentPadding = PaddingValues(bottom = 8.dp),
|
contentPadding = PaddingValues(bottom = 16.dp),
|
||||||
) {
|
) {
|
||||||
stickyHeader {
|
stickyHeader {
|
||||||
CharacterSheetHeader(
|
CharacterSheetHeader(
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ class SpellsActionViewModel @Inject constructor(
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
) : AndroidViewModel(application) {
|
) : AndroidViewModel(application) {
|
||||||
private val characterName = savedStateHandle.characterSheetArgument.name
|
private val characterName = savedStateHandle.characterSheetArgument.name
|
||||||
private val character: CharacterSheet
|
private var character: CharacterSheet? = null
|
||||||
get() = characterRepository.data.value.getValue(characterName)
|
private var characterFire: CharacterSheetFire? = null
|
||||||
|
|
||||||
private val _spells = mutableStateOf<List<Pair<SpellHeaderUio, List<SpellUio>>>>(emptyList())
|
private val _spells = mutableStateOf<List<Pair<SpellHeaderUio, List<SpellUio>>>>(emptyList())
|
||||||
val spells: State<List<Pair<SpellHeaderUio, List<SpellUio>>>> get() = _spells
|
val spells: State<List<Pair<SpellHeaderUio, List<SpellUio>>>> get() = _spells
|
||||||
|
|
@ -60,9 +60,11 @@ class SpellsActionViewModel @Inject constructor(
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
characterRepository.data
|
characterRepository.data
|
||||||
.combine(spellRepository.spells) { sheets, spells ->
|
.combine(spellRepository.spells) { sheets, spells ->
|
||||||
|
character = sheets.getValue(characterName)
|
||||||
Struct(sheets = sheets, spells = spells)
|
Struct(sheets = sheets, spells = spells)
|
||||||
}
|
}
|
||||||
.combine(firebaseRepository.getCharacter(character = characterName)) { struct, fire ->
|
.combine(firebaseRepository.getCharacter(character = characterName)) { struct, fire ->
|
||||||
|
characterFire = fire
|
||||||
struct.also { it.fire = fire }
|
struct.also { it.fire = fire }
|
||||||
}
|
}
|
||||||
.collect { data ->
|
.collect { data ->
|
||||||
|
|
@ -136,18 +138,20 @@ class SpellsActionViewModel @Inject constructor(
|
||||||
character = characterName,
|
character = characterName,
|
||||||
spell = name,
|
spell = name,
|
||||||
)
|
)
|
||||||
return when (character.isWarlock) {
|
return when (character?.isWarlock?: false) {
|
||||||
true -> false
|
true -> false
|
||||||
else -> character.highestSpellLevel() > (assignedSpell?.spell?.level ?: 1)
|
else -> (character?.highestSpellLevel() ?: 1) > (assignedSpell?.spell?.level ?: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun prepareSpellCast(name: String) {
|
fun prepareSpellCast(name: String) {
|
||||||
|
val character = character
|
||||||
|
val characterFire = characterFire
|
||||||
val assignedSpell = spellRepository.find(
|
val assignedSpell = spellRepository.find(
|
||||||
character = characterName,
|
character = characterName,
|
||||||
spell = name,
|
spell = name,
|
||||||
)
|
)
|
||||||
if (assignedSpell != null) {
|
if (assignedSpell != null && character != null && characterFire != null) {
|
||||||
val icon = assignedSpell.effect?.faces?.icon ?: R.drawable.ic_d20_24
|
val icon = assignedSpell.effect?.faces?.icon ?: R.drawable.ic_d20_24
|
||||||
val base = assignedSpell.effect?.toString(character = character, level = 1) ?: ""
|
val base = assignedSpell.effect?.toString(character = character, level = 1) ?: ""
|
||||||
_preparedSpellLevel.value = SpellChooserUio(
|
_preparedSpellLevel.value = SpellChooserUio(
|
||||||
|
|
@ -156,7 +160,7 @@ class SpellsActionViewModel @Inject constructor(
|
||||||
size = max(0, character.highestSpellLevel() + 1 - assignedSpell.spell.level)
|
size = max(0, character.highestSpellLevel() + 1 - assignedSpell.spell.level)
|
||||||
) { index ->
|
) { index ->
|
||||||
val level = assignedSpell.spell.level + index
|
val level = assignedSpell.spell.level + index
|
||||||
val remaining = character.spell(level)
|
val remaining = characterFire.spell(level)
|
||||||
val max = character.spell(level)
|
val max = character.spell(level)
|
||||||
|
|
||||||
SpellLevelUio(
|
SpellLevelUio(
|
||||||
|
|
@ -179,8 +183,8 @@ class SpellsActionViewModel @Inject constructor(
|
||||||
val spell = spellRepository.find(character = characterName, spell = id)
|
val spell = spellRepository.find(character = characterName, spell = id)
|
||||||
return onCastSpell(
|
return onCastSpell(
|
||||||
id = id,
|
id = id,
|
||||||
level = when (character.isWarlock) {
|
level = when (character?.isWarlock ?: false) {
|
||||||
true -> character.firstSpellSlot() ?: 1
|
true -> character?.firstSpellSlot() ?: 1
|
||||||
else -> spell?.spell?.level ?: 1
|
else -> spell?.spell?.level ?: 1
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ fun AlterationPageContent(
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
contentPadding = PaddingValues(vertical = 8.dp),
|
contentPadding = PaddingValues(top = 8.dp, bottom = 16.dp),
|
||||||
) {
|
) {
|
||||||
items(items = alterations.value) {
|
items(items = alterations.value) {
|
||||||
RollAlteration(
|
RollAlteration(
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
package com.pixelized.rplexicon.ui.screens.character.pages.alteration
|
package com.pixelized.rplexicon.ui.screens.character.pages.alteration
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.pixelized.rplexicon.repository.authentication.FirebaseRepository
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.AlterationDetailUio
|
import com.pixelized.rplexicon.ui.screens.rolls.composable.AlterationDetailUio
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
|
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
|
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
|
||||||
|
import com.pixelized.rplexicon.utilitary.extentions.context
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -21,9 +23,11 @@ import javax.inject.Inject
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class AlterationViewModel @Inject constructor(
|
class AlterationViewModel @Inject constructor(
|
||||||
private val alterationRepository: AlterationRepository,
|
private val alterationRepository: AlterationRepository,
|
||||||
|
private val descriptionRepository: DescriptionRepository,
|
||||||
private val factory: AlterationFactory,
|
private val factory: AlterationFactory,
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
) : ViewModel() {
|
application: Application
|
||||||
|
) : AndroidViewModel(application) {
|
||||||
private val character = savedStateHandle.characterSheetArgument.name
|
private val character = savedStateHandle.characterSheetArgument.name
|
||||||
|
|
||||||
private val _alterations = mutableStateOf<List<RollAlterationUio>>(emptyList())
|
private val _alterations = mutableStateOf<List<RollAlterationUio>>(emptyList())
|
||||||
|
|
@ -56,12 +60,16 @@ class AlterationViewModel @Inject constructor(
|
||||||
fun showAlterationDetail(id: String) {
|
fun showAlterationDetail(id: String) {
|
||||||
val alteration = alterationRepository.getAlterations(character = character)
|
val alteration = alterationRepository.getAlterations(character = character)
|
||||||
.firstOrNull { it.name == id }
|
.firstOrNull { it.name == id }
|
||||||
|
val description = descriptionRepository.find(name = alteration?.name)
|
||||||
|
|
||||||
if (alteration != null) {
|
if (alteration != null) {
|
||||||
_alterationDetail.value = AlterationDetailUio(
|
_alterationDetail.value = AlterationDetailUio(
|
||||||
name = id,
|
name = id,
|
||||||
|
original = description?.original,
|
||||||
source = alteration.source,
|
source = alteration.source,
|
||||||
target = alteration.target,
|
target = alteration.target,
|
||||||
description = alteration.description
|
description = description?.description
|
||||||
|
?: context.getString(R.string.no_available_description)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,18 @@ import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.business.DiceThrowUseCase
|
import com.pixelized.rplexicon.business.DiceThrowUseCase
|
||||||
import com.pixelized.rplexicon.model.DiceThrow
|
import com.pixelized.rplexicon.model.DiceThrow
|
||||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||||
|
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.AlterationDetailUio
|
import com.pixelized.rplexicon.ui.screens.rolls.composable.AlterationDetailUio
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
|
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
|
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
|
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.factory.DiceFactory
|
import com.pixelized.rplexicon.ui.screens.rolls.factory.DiceFactory
|
||||||
|
import com.pixelized.rplexicon.utilitary.extentions.context
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.switch
|
import com.pixelized.rplexicon.utilitary.extentions.switch
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
@ -24,6 +27,7 @@ import javax.inject.Inject
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class RollOverlayViewModel @Inject constructor(
|
class RollOverlayViewModel @Inject constructor(
|
||||||
private val alterationRepository: AlterationRepository,
|
private val alterationRepository: AlterationRepository,
|
||||||
|
private val descriptionRepository: DescriptionRepository,
|
||||||
private val rollUseCase: DiceThrowUseCase,
|
private val rollUseCase: DiceThrowUseCase,
|
||||||
private val diceFactory: DiceFactory,
|
private val diceFactory: DiceFactory,
|
||||||
private val alterationFactory: AlterationFactory,
|
private val alterationFactory: AlterationFactory,
|
||||||
|
|
@ -98,12 +102,16 @@ class RollOverlayViewModel @Inject constructor(
|
||||||
val alteration = diceThrow?.character?.let { character ->
|
val alteration = diceThrow?.character?.let { character ->
|
||||||
alterationRepository.getAlterations(character = character).firstOrNull { it.name == id }
|
alterationRepository.getAlterations(character = character).firstOrNull { it.name == id }
|
||||||
}
|
}
|
||||||
|
val description = descriptionRepository.find(name = alteration?.name)
|
||||||
|
|
||||||
if (alteration != null) {
|
if (alteration != null) {
|
||||||
_alterationDetail.value = AlterationDetailUio(
|
_alterationDetail.value = AlterationDetailUio(
|
||||||
name = id,
|
name = id,
|
||||||
|
original = description?.original,
|
||||||
source = alteration.source,
|
source = alteration.source,
|
||||||
target = alteration.target,
|
target = alteration.target,
|
||||||
description = alteration.description
|
description = description?.description
|
||||||
|
?: context.getString(R.string.no_available_description)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -25,6 +27,7 @@ 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.res.stringResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
@ -37,11 +40,13 @@ import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
@Stable
|
@Stable
|
||||||
data class AlterationDetailUio(
|
data class AlterationDetailUio(
|
||||||
val name: String,
|
val name: String,
|
||||||
|
val original: String?,
|
||||||
val source: String,
|
val source: String,
|
||||||
val target: String,
|
val target: String,
|
||||||
val description: String,
|
val description: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AlterationDetail(
|
fun AlterationDetail(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|
@ -65,22 +70,38 @@ fun AlterationDetail(
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.Top,
|
verticalAlignment = Alignment.Top,
|
||||||
) {
|
) {
|
||||||
Text(
|
FlowRow(
|
||||||
modifier = Modifier.padding(top = 16.dp),
|
modifier = Modifier.padding(top = 16.dp),
|
||||||
style = MaterialTheme.typography.titleMedium,
|
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
maxLines = 1,
|
) {
|
||||||
overflow = TextOverflow.Ellipsis,
|
Text(
|
||||||
text = AnnotatedString(
|
modifier = Modifier.alignByBaseline(),
|
||||||
text = detail.name,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
spanStyles = listOf(
|
maxLines = 1,
|
||||||
AnnotatedString.Range(
|
overflow = TextOverflow.Ellipsis,
|
||||||
item = MaterialTheme.lexicon.typography.bodyDropCapSpan,
|
text = AnnotatedString(
|
||||||
start = 0,
|
text = detail.name,
|
||||||
end = Integer.min(1, detail.name.length),
|
spanStyles = listOf(
|
||||||
|
AnnotatedString.Range(
|
||||||
|
item = MaterialTheme.lexicon.typography.bodyDropCapSpan,
|
||||||
|
start = 0,
|
||||||
|
end = Integer.min(1, detail.name.length),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
detail.original?.let {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.alignByBaseline(),
|
||||||
|
fontWeight = FontWeight.Light,
|
||||||
|
fontStyle = FontStyle.Italic,
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
text = it,
|
||||||
)
|
)
|
||||||
),
|
}
|
||||||
)
|
}
|
||||||
IconButton(onClick = onClose) {
|
IconButton(onClick = onClose) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
|
|
@ -123,6 +144,7 @@ private fun AlterationDetailPreview() {
|
||||||
AlterationDetail(
|
AlterationDetail(
|
||||||
detail = AlterationDetailUio(
|
detail = AlterationDetailUio(
|
||||||
name = "Rage",
|
name = "Rage",
|
||||||
|
original = "Rage",
|
||||||
source = "Barbare",
|
source = "Barbare",
|
||||||
target = "Barbare",
|
target = "Barbare",
|
||||||
description = "\"En combat, vous vous battez avec une férocité bestiale. Durant votre tour, vous pouvez entrer en rage en utilisant une action bonus. En rage, vous gagnez les bénéfices suivants si vous ne portez pas d'armure lourde :\n" +
|
description = "\"En combat, vous vous battez avec une férocité bestiale. Durant votre tour, vous pouvez entrer en rage en utilisant une action bonus. En rage, vous gagnez les bénéfices suivants si vous ne portez pas d'armure lourde :\n" +
|
||||||
|
|
|
||||||
|
|
@ -5,48 +5,58 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||||
import com.pixelized.rplexicon.ui.navigation.screens.spellDetailArgument
|
import com.pixelized.rplexicon.ui.navigation.screens.spellDetailArgument
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.local.icon
|
import com.pixelized.rplexicon.utilitary.extentions.local.icon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.local.label
|
import com.pixelized.rplexicon.utilitary.extentions.local.label
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SpellDetailViewModel @Inject constructor(
|
class SpellDetailViewModel @Inject constructor(
|
||||||
|
spellRepository: SpellRepository,
|
||||||
|
descriptionRepository: DescriptionRepository,
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
repository: SpellRepository
|
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
val spell: State<SpellDetailUio?>
|
val spell: State<SpellDetailUio?>
|
||||||
val error: SharedFlow<FetchErrorUio>
|
val error: Flow<FetchErrorUio>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val argument = savedStateHandle.spellDetailArgument
|
val argument = savedStateHandle.spellDetailArgument
|
||||||
val assignedSpell = repository.find(
|
val description = descriptionRepository.find(
|
||||||
|
name = argument.spell,
|
||||||
|
)
|
||||||
|
val spell = spellRepository.find(
|
||||||
character = argument.character,
|
character = argument.character,
|
||||||
spell = argument.spell,
|
spell = argument.spell,
|
||||||
)?.let {
|
)
|
||||||
|
|
||||||
|
val assignedSpell = if (spell != null && description != null) {
|
||||||
SpellDetailUio(
|
SpellDetailUio(
|
||||||
icon = it.spell.school.icon,
|
icon = spell.spell.school.icon,
|
||||||
name = it.spell.name,
|
name = spell.spell.name,
|
||||||
translated = it.spell.originalName,
|
translated = description.original,
|
||||||
level = "${it.spell.level}",
|
level = "${spell.spell.level}",
|
||||||
school = it.spell.school.label,
|
school = spell.spell.school.label,
|
||||||
castingTime = it.spell.castingTime,
|
castingTime = spell.spell.castingTime,
|
||||||
range = it.spell.range,
|
range = spell.spell.range,
|
||||||
requirement = it.spell.requirement,
|
requirement = spell.spell.requirement,
|
||||||
duration = it.spell.duration,
|
duration = spell.spell.duration,
|
||||||
description = it.spell.description,
|
description = description.description,
|
||||||
ritual = it.spell.ritual,
|
ritual = spell.spell.ritual,
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
spell = mutableStateOf(assignedSpell)
|
this.spell = mutableStateOf(assignedSpell)
|
||||||
error = MutableSharedFlow<FetchErrorUio>().also { flow ->
|
|
||||||
|
this.error = MutableSharedFlow<FetchErrorUio>().also { flow ->
|
||||||
if (assignedSpell == null) {
|
if (assignedSpell == null) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
flow.tryEmit(FetchErrorUio.Default)
|
flow.tryEmit(FetchErrorUio.Default)
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,8 @@
|
||||||
<string name="alteration_source">Source : %1$s</string>
|
<string name="alteration_source">Source : %1$s</string>
|
||||||
<string name="alteration_target">Cible : %1$s</string>
|
<string name="alteration_target">Cible : %1$s</string>
|
||||||
|
|
||||||
|
<string name="no_available_description">Aucune description disponnible</string>
|
||||||
|
|
||||||
<string name="token_label_title">Capacité</string>
|
<string name="token_label_title">Capacité</string>
|
||||||
<string name="token_label_rage">Rage</string>
|
<string name="token_label_rage">Rage</string>
|
||||||
<string name="token_label_relentless_endurance">Endurance Implacable</string>
|
<string name="token_label_relentless_endurance">Endurance Implacable</string>
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,8 @@
|
||||||
<string name="alteration_source">Source: %1$s</string>
|
<string name="alteration_source">Source: %1$s</string>
|
||||||
<string name="alteration_target">Target: %1$s</string>
|
<string name="alteration_target">Target: %1$s</string>
|
||||||
|
|
||||||
|
<string name="no_available_description">No available description</string>
|
||||||
|
|
||||||
<string name="token_label_title">Skill</string>
|
<string name="token_label_title">Skill</string>
|
||||||
<string name="token_label_rage">Rage</string>
|
<string name="token_label_rage">Rage</string>
|
||||||
<string name="token_label_relentless_endurance">Relentless Endurance</string>
|
<string name="token_label_relentless_endurance">Relentless Endurance</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue