Add inventory and equipment feature.
This commit is contained in:
parent
2be527abf9
commit
daea5fd6dc
74 changed files with 1609 additions and 574 deletions
|
|
@ -6,15 +6,17 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||
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.repository.data.LexiconRepository
|
||||
import com.pixelized.rplexicon.repository.data.LocationRepository
|
||||
import com.pixelized.rplexicon.repository.data.QuestRepository
|
||||
import com.pixelized.rplexicon.repository.data.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.EquipmentRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.InventoryRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LexiconRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LocationRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.QuestRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
|
|
@ -34,6 +36,8 @@ class LauncherViewModel @Inject constructor(
|
|||
spellRepository: SpellRepository,
|
||||
skillRepository: SkillRepository,
|
||||
descriptionRepository: DescriptionRepository,
|
||||
inventoryRepository: InventoryRepository,
|
||||
equipmentRepository: EquipmentRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _error = MutableSharedFlow<String>()
|
||||
|
|
@ -76,7 +80,7 @@ class LauncherViewModel @Inject constructor(
|
|||
_error.tryEmit("CharacterSheet fail to update")
|
||||
}
|
||||
}
|
||||
val descriptionSheet = async {
|
||||
val description = async {
|
||||
try {
|
||||
descriptionRepository.fetchDescription()
|
||||
} catch (exception: Exception) {
|
||||
|
|
@ -84,7 +88,23 @@ class LauncherViewModel @Inject constructor(
|
|||
_error.tryEmit("Skill/Spell description fail to update")
|
||||
}
|
||||
}
|
||||
awaitAll(lexicon, location, quest, characterSheet, descriptionSheet)
|
||||
val inventory = async {
|
||||
try {
|
||||
inventoryRepository.fetchInventory()
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message, exception)
|
||||
_error.tryEmit("Inventories fail to update")
|
||||
}
|
||||
}
|
||||
val equipment = async {
|
||||
try {
|
||||
equipmentRepository.fetchEquipment()
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message, exception)
|
||||
_error.tryEmit("Equipments fail to update")
|
||||
}
|
||||
}
|
||||
awaitAll(characterSheet)
|
||||
|
||||
val alteration = async {
|
||||
try {
|
||||
|
|
@ -96,7 +116,7 @@ class LauncherViewModel @Inject constructor(
|
|||
}
|
||||
val action = async {
|
||||
try {
|
||||
actionRepository.fetchActions()
|
||||
actionRepository.fetchActions(characters = characterSheetRepository.data.value)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message, exception)
|
||||
_error.tryEmit("Action fail to update")
|
||||
|
|
@ -118,7 +138,10 @@ class LauncherViewModel @Inject constructor(
|
|||
_error.tryEmit("Skill fail to update")
|
||||
}
|
||||
}
|
||||
awaitAll(alteration, action, spell, skill)
|
||||
awaitAll(
|
||||
lexicon, location, quest, description, inventory,
|
||||
equipment, alteration, action, spell, skill,
|
||||
)
|
||||
|
||||
isLoading = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,25 +6,31 @@ import androidx.activity.ComponentActivity
|
|||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.CutCornerShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Snackbar
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.pixelized.rplexicon.ui.composable.BlurredOverlayHost
|
||||
import com.pixelized.rplexicon.ui.navigation.ScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.BlurredRollOverlayHostState
|
||||
|
|
@ -32,6 +38,7 @@ import com.pixelized.rplexicon.ui.screens.rolls.RollOverlay
|
|||
import com.pixelized.rplexicon.ui.screens.rolls.RollOverlayViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.rememberBlurredRollOverlayHostState
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
val LocalActivity = staticCompositionLocalOf<Activity> {
|
||||
|
|
@ -97,10 +104,32 @@ class MainActivity : ComponentActivity() {
|
|||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
val isDarkTheme = isSystemInDarkTheme()
|
||||
val elevation = remember {
|
||||
derivedStateOf { if (isDarkTheme) 2.dp else 0.dp }
|
||||
}
|
||||
SnackbarHost(
|
||||
modifier = Modifier.navigationBarsPadding(),
|
||||
hostState = LocalSnack.current,
|
||||
)
|
||||
) {
|
||||
Snackbar(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.ddBorder(
|
||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||
outline = remember { CutCornerShape(size = 16.dp) },
|
||||
),
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
elevation = elevation.value
|
||||
),
|
||||
content = {
|
||||
Text(
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
text = it.visuals.message,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
BackHandler(enabled = overlay.isOverlayVisible) {
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import com.pixelized.rplexicon.model.DiceThrow
|
|||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.model.Skill
|
||||
import com.pixelized.rplexicon.model.Throw
|
||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
|
|
|
|||
52
app/src/main/java/com/pixelized/rplexicon/model/Equipment.kt
Normal file
52
app/src/main/java/com/pixelized/rplexicon/model/Equipment.kt
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package com.pixelized.rplexicon.model
|
||||
|
||||
data class Equipment(
|
||||
val head: String? = null,
|
||||
val face: String? = null,
|
||||
val neck: String? = null,
|
||||
val shoulder: String? = null,
|
||||
val body: String? = null,
|
||||
val chest: String? = null,
|
||||
val arm: String? = null,
|
||||
val hand: String? = null,
|
||||
val ring1: String? = null,
|
||||
val ring2: String? = null,
|
||||
val waist: String? = null,
|
||||
val foot: String? = null,
|
||||
val mainHand: String? = null,
|
||||
val offHand: String? = null,
|
||||
) {
|
||||
class Builder(
|
||||
var head: String? = null,
|
||||
var face: String? = null,
|
||||
var neck: String? = null,
|
||||
var shoulder: String? = null,
|
||||
var body: String? = null,
|
||||
var chest: String? = null,
|
||||
var arm: String? = null,
|
||||
var hand: String? = null,
|
||||
var ring1: String? = null,
|
||||
var ring2: String? = null,
|
||||
var waist: String? = null,
|
||||
var foot: String? = null,
|
||||
var mainHand: String? = null,
|
||||
var offHand: String? = null,
|
||||
) {
|
||||
fun build(): Equipment = Equipment(
|
||||
head = head,
|
||||
face = face,
|
||||
neck = neck,
|
||||
shoulder = shoulder,
|
||||
body = body,
|
||||
chest = chest,
|
||||
arm = arm,
|
||||
hand = hand,
|
||||
ring1 = ring1,
|
||||
ring2 = ring2,
|
||||
waist = waist,
|
||||
foot = foot,
|
||||
mainHand = mainHand,
|
||||
offHand = offHand,
|
||||
)
|
||||
}
|
||||
}
|
||||
42
app/src/main/java/com/pixelized/rplexicon/model/Inventory.kt
Normal file
42
app/src/main/java/com/pixelized/rplexicon/model/Inventory.kt
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package com.pixelized.rplexicon.model
|
||||
|
||||
data class Inventory(
|
||||
val items: List<Item>,
|
||||
) {
|
||||
class Builder(
|
||||
val items: MutableList<Item.Builder> = mutableListOf(),
|
||||
) {
|
||||
fun build(): Inventory = Inventory(
|
||||
items = items.map { it.build() }
|
||||
)
|
||||
|
||||
fun find(container: String): Item.Builder? {
|
||||
return items.firstOrNull { it.find(name = container) != null }
|
||||
}
|
||||
}
|
||||
|
||||
data class Item(
|
||||
val name: String,
|
||||
val amount: String?,
|
||||
val items: List<Item>,
|
||||
) {
|
||||
class Builder(
|
||||
var name: String,
|
||||
var amount: String? = null,
|
||||
val items: MutableList<Builder> = mutableListOf(),
|
||||
) {
|
||||
fun build(): Item = Item(
|
||||
name = name,
|
||||
amount = amount,
|
||||
items = items.map { it.build() }
|
||||
)
|
||||
|
||||
fun find(name: String): Builder? {
|
||||
return when (this.name) {
|
||||
name -> this
|
||||
else -> items.firstOrNull { it.find(name = name) != null }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
|
||||
|
||||
object Sheet {
|
||||
object Lexicon {
|
||||
const val ID = "1oL9Nu5y37BPEbKxHre4TN9o8nrgy2JQoON4RRkdAHMs"
|
||||
|
||||
const val LEXICON = "Lexique"
|
||||
const val QUEST_JOURNAL = "Journal de quêtes"
|
||||
const val MAP = "Lieux"
|
||||
const val MARQUEE = "Points d'intérêt"
|
||||
}
|
||||
|
||||
object Character {
|
||||
const val ID = "1fHfzeb8y5u9lEQB1iI-jBEhqu7YSip5sAajXcXK7VJ8"
|
||||
|
||||
const val CHARACTER = "Feuille de personnage"
|
||||
const val ATTACK = "Attaques"
|
||||
const val MAGIC = "Magies"
|
||||
const val SKILL = "Capacités"
|
||||
const val MAGIC_LEXICON = "Lexique magique"
|
||||
const val ALTERATION = "Altérations"
|
||||
const val DESCRIPTION = "Descriptions"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
|
||||
object LexiconBinder {
|
||||
const val ID = "1oL9Nu5y37BPEbKxHre4TN9o8nrgy2JQoON4RRkdAHMs"
|
||||
|
||||
const val LEXICON = "Lexique"
|
||||
const val QUEST_JOURNAL = "Journal de quêtes"
|
||||
const val MAP = "Lieux"
|
||||
const val MARQUEE = "Points d'intérêt"
|
||||
}
|
||||
|
||||
object CharacterBinder {
|
||||
const val ID = "1fHfzeb8y5u9lEQB1iI-jBEhqu7YSip5sAajXcXK7VJ8"
|
||||
|
||||
const val CHARACTER = "Feuille de personnage"
|
||||
const val ATTACK = "Attaques"
|
||||
const val MAGIC = "Magies"
|
||||
const val SKILL = "Capacités"
|
||||
const val MAGIC_LEXICON = "Lexique magique"
|
||||
const val ALTERATION = "Altérations"
|
||||
const val DESCRIPTION = "Descriptions"
|
||||
const val INVENTORY = "Inventaires"
|
||||
const val EQUIPMENT = "Équipements"
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.model.Attack
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.repository.parser.AttackParser
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
|
|
@ -13,7 +15,6 @@ import javax.inject.Singleton
|
|||
@Singleton
|
||||
class ActionRepository @Inject constructor(
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val actionParser: AttackParser,
|
||||
) {
|
||||
private val _data = MutableStateFlow<Map<String, List<Attack>>>(emptyMap())
|
||||
|
|
@ -31,12 +32,12 @@ class ActionRepository @Inject constructor(
|
|||
}
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchActions() {
|
||||
suspend fun fetchActions(characters: Map<String, CharacterSheet>) {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.ATTACK)
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.ATTACK)
|
||||
val data = actionParser.parse(
|
||||
value = request.execute(),
|
||||
charactersSheets = characterSheetRepository.data.value
|
||||
charactersSheets = characters
|
||||
)
|
||||
_data.emit(data)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.model.Alteration
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.repository.parser.alteration.AlterationParser
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
|
|
@ -86,7 +87,7 @@ class AlterationRepository @Inject constructor(
|
|||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchAlterationSheet(sheets: List<CharacterSheet>) {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.ALTERATION)
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.ALTERATION)
|
||||
val data = alterationParser.parse(values = request.execute(), sheets = sheets)
|
||||
_assignedAlterations.emit(data)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.repository.parser.CharacterSheetParser
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ class CharacterSheetRepository @Inject constructor(
|
|||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchCharacterSheet() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.CHARACTER)
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.CHARACTER)
|
||||
val data = characterSheetParser.parse(value = request.execute())
|
||||
_data.emit(data)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.model.Description
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.repository.parser.DescriptionParser
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
|
|
@ -26,7 +27,7 @@ class DescriptionRepository @Inject constructor(
|
|||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchDescription() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.DESCRIPTION)
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.DESCRIPTION)
|
||||
val data = parser.parse(data = request.execute())
|
||||
_data.tryEmit(data)
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.model.Equipment
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.repository.parser.inventory.EquipmentParser
|
||||
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 EquipmentRepository @Inject constructor(
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val equipmentParser: EquipmentParser,
|
||||
) {
|
||||
private val _data = MutableStateFlow<Map<String, Equipment>>(emptyMap())
|
||||
val data: StateFlow<Map<String, Equipment>> get() = _data
|
||||
|
||||
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||
private set
|
||||
|
||||
fun find(name: String?): Equipment? = _data.value[name]
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchEquipment() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.EQUIPMENT)
|
||||
val data = equipmentParser.parse(data = request.execute())
|
||||
_data.tryEmit(data)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.model.Inventory
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.repository.parser.inventory.InventoryParser
|
||||
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 InventoryRepository @Inject constructor(
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val inventoryParser: InventoryParser,
|
||||
) {
|
||||
private val _data = MutableStateFlow<Map<String, Inventory>>(emptyMap())
|
||||
val data: StateFlow<Map<String, Inventory>> get() = _data
|
||||
|
||||
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||
private set
|
||||
|
||||
fun find(name: String?): Inventory? = _data.value[name]
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchInventory() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.INVENTORY)
|
||||
val data = inventoryParser.parse(data = request.execute())
|
||||
_data.tryEmit(data)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.model.Skill
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.repository.parser.SkillParser
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
|
|
@ -28,7 +29,7 @@ class SkillRepository @Inject constructor(
|
|||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchSkills() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.SKILL)
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.SKILL)
|
||||
val skills = skillParser.parse(data = request.execute())
|
||||
|
||||
_skills.emit(skills)
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.model.AssignedSpell
|
||||
import com.pixelized.rplexicon.model.Spell
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.repository.parser.spell.AssignedSpellParser
|
||||
import com.pixelized.rplexicon.repository.parser.spell.SpellBookParser
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
|
|
@ -39,8 +40,8 @@ class SpellRepository @Inject constructor(
|
|||
suspend fun fetchSpells() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val (lexicon, magic) = awaitAll(
|
||||
async { sheet.get(Sheet.Character.ID, Sheet.Character.MAGIC_LEXICON).execute() },
|
||||
async { sheet.get(Sheet.Character.ID, Sheet.Character.MAGIC).execute() },
|
||||
async { sheet.get(CharacterBinder.ID, CharacterBinder.MAGIC_LEXICON).execute() },
|
||||
async { sheet.get(CharacterBinder.ID, CharacterBinder.MAGIC).execute() },
|
||||
)
|
||||
val spellsBook = spellBookParser.parse(data = lexicon)
|
||||
val assignedSpells = assignedSpellParser.parse(data = magic, spells = spellsBook)
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.lexicon
|
||||
|
||||
import com.pixelized.rplexicon.repository.parser.LexiconParser
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.LexiconBinder
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -28,7 +29,7 @@ class LexiconRepository @Inject constructor(
|
|||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchLexicon() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.LEXICON)
|
||||
val request = sheet.get(LexiconBinder.ID, LexiconBinder.LEXICON)
|
||||
val data = lexiconParser.parse(data = request.execute())
|
||||
_data.tryEmit(data)
|
||||
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.lexicon
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.repository.parser.LocationParser
|
||||
import com.pixelized.rplexicon.repository.parser.MarqueeParser
|
||||
import com.pixelized.rplexicon.model.Location
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.LexiconBinder
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import kotlinx.coroutines.async
|
||||
|
|
@ -34,8 +35,8 @@ class LocationRepository @Inject constructor(
|
|||
suspend fun fetchLocation() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val (map, marquee) = awaitAll(
|
||||
async { sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.MAP).execute() },
|
||||
async { sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.MARQUEE).execute() },
|
||||
async { sheet.get(LexiconBinder.ID, LexiconBinder.MAP).execute() },
|
||||
async { sheet.get(LexiconBinder.ID, LexiconBinder.MARQUEE).execute() },
|
||||
)
|
||||
updateData(map = map, marquee = marquee)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
|
|
@ -64,6 +65,6 @@ class LocationRepository @Inject constructor(
|
|||
|
||||
companion object {
|
||||
const val SHEET_URL =
|
||||
"https://docs.google.com/spreadsheets/d/${Sheet.Lexicon.ID}/edit#gid=1985553511"
|
||||
"https://docs.google.com/spreadsheets/d/${LexiconBinder.ID}/edit#gid=1985553511"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
package com.pixelized.rplexicon.repository.data.lexicon
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.repository.parser.QuestParser
|
||||
import com.pixelized.rplexicon.model.Quest
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.LexiconBinder
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -25,7 +26,7 @@ class QuestRepository @Inject constructor(
|
|||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchQuests() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.QUEST_JOURNAL)
|
||||
val request = sheet.get(LexiconBinder.ID, LexiconBinder.QUEST_JOURNAL)
|
||||
val data = request.execute()
|
||||
updateData(data = data)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.pixelized.rplexicon.repository.parser
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.checkSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||
|
||||
inline fun <reified T> parserScope(
|
||||
noinline block: SheetParserScope<T>.() -> T
|
||||
): T {
|
||||
return SheetParserScope<T>().parse(block)
|
||||
}
|
||||
|
||||
class SheetParserScope<T> {
|
||||
private var structure: Map<String, Int> = hashMapOf()
|
||||
|
||||
fun updateStructure(row: Any, columns: List<String>) {
|
||||
structure = row.checkSheetStructure(model = columns)
|
||||
}
|
||||
|
||||
fun parse(block: SheetParserScope<T>.() -> T): T {
|
||||
return this.block()
|
||||
}
|
||||
|
||||
fun ValueRange.forEachRow(block: (index: Int, row: List<*>) -> Unit) {
|
||||
val sheet = this.values.sheet()
|
||||
sheet?.mapNotNull { it as? List<*> }?.forEachIndexed(block)
|
||||
}
|
||||
|
||||
fun Any?.toItem(): String? =
|
||||
this.toString().takeIf { it.isNotBlank() }
|
||||
|
||||
fun List<*>.parse(column: String): String? =
|
||||
getOrNull(structure.getValue(column))?.toItem()
|
||||
|
||||
fun List<*>.parseInt(column: String): Int? =
|
||||
parse(column)?.toIntOrNull()
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package com.pixelized.rplexicon.repository.parser.inventory
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.model.Equipment
|
||||
import com.pixelized.rplexicon.repository.parser.parserScope
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import javax.inject.Inject
|
||||
|
||||
class EquipmentParser @Inject constructor() {
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
fun parse(data: ValueRange): Map<String, Equipment> = parserScope {
|
||||
lateinit var characters: List<String>
|
||||
val equipments = hashMapOf<String, Equipment.Builder>()
|
||||
|
||||
data.forEachRow { index, row ->
|
||||
when (index) {
|
||||
// ignore the first column
|
||||
0 -> characters = row.drop(1).map { it.toString() }
|
||||
|
||||
else -> row.drop(1).forEachIndexed { column, item ->
|
||||
val character = characters[column]
|
||||
equipments.getEquipment(name = character).let {
|
||||
when (row[0]) {
|
||||
HEAD -> it.head = item.toItem()
|
||||
FACE -> it.face = item.toItem()
|
||||
NECK -> it.neck = item.toItem()
|
||||
SHOULDER -> it.shoulder = item.toItem()
|
||||
BODY -> it.body = item.toItem()
|
||||
CHEST -> it.chest = item.toItem()
|
||||
ARM -> it.arm = item.toItem()
|
||||
HAND -> it.hand = item.toItem()
|
||||
RING_1 -> it.ring1 = item.toItem()
|
||||
RING_2 -> it.ring2 = item.toItem()
|
||||
WAIST -> it.waist = item.toItem()
|
||||
FOOT -> it.foot = item.toItem()
|
||||
MAIN_HAND -> it.mainHand = item.toItem()
|
||||
OFF_HAND -> it.offHand = item.toItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return@parserScope characters.associateWith {
|
||||
equipments.getEquipment(name = it).build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun HashMap<String, Equipment.Builder>.getEquipment(name: String) =
|
||||
this.getOrPut(name) { Equipment.Builder() }
|
||||
|
||||
companion object {
|
||||
private const val HEAD = "Tête"
|
||||
private const val FACE = "Visage"
|
||||
private const val NECK = "Gorge"
|
||||
private const val SHOULDER = "Épaules"
|
||||
private const val BODY = "Corp"
|
||||
private const val CHEST = "Torse"
|
||||
private const val ARM = "Bras"
|
||||
private const val HAND = "Mains"
|
||||
private const val RING_1 = "Anneau 1"
|
||||
private const val RING_2 = "Anneau 2"
|
||||
private const val WAIST = "Taille"
|
||||
private const val FOOT = "Pieds"
|
||||
private const val MAIN_HAND = "Main droite"
|
||||
private const val OFF_HAND = "Main gauche"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.pixelized.rplexicon.repository.parser.inventory
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.model.Inventory
|
||||
import com.pixelized.rplexicon.repository.parser.parserScope
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import javax.inject.Inject
|
||||
|
||||
class InventoryParser @Inject constructor() {
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
fun parse(data: ValueRange): Map<String, Inventory> = parserScope {
|
||||
val inventories = hashMapOf<String, Inventory.Builder>()
|
||||
|
||||
data.forEachRow { index, row ->
|
||||
when {
|
||||
index == 0 -> updateStructure(row = row, columns = COLUMNS)
|
||||
|
||||
row.isNotEmpty() -> {
|
||||
val character = row[0]?.toItem()
|
||||
val container = row.parse(column = CONTAINER)
|
||||
val name = row.parse(column = NAME)
|
||||
val amount = row.parse(column = AMOUNT)
|
||||
|
||||
if (character != null && name != null) {
|
||||
// retrieve the character inventory
|
||||
val inventory = inventories.getOrPut(character) { Inventory.Builder() }
|
||||
// make a item builder
|
||||
val item = Inventory.Item.Builder(
|
||||
name = name,
|
||||
amount = amount,
|
||||
)
|
||||
// add the item to its container or by default to the inventory.
|
||||
val isAdded = container?.let {
|
||||
inventory.find(container = it)?.items?.add(item)
|
||||
} ?: false
|
||||
if (isAdded.not()) {
|
||||
inventory.items.add(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return@parserScope inventories.mapValues { entry -> entry.value.build() }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CONTAINER = "Contenant"
|
||||
private const val NAME = "Name"
|
||||
private const val AMOUNT = "Quantité"
|
||||
private const val THROW = "Effet"
|
||||
private val COLUMNS = listOf(CONTAINER, NAME, AMOUNT, THROW)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,13 +15,13 @@ import androidx.compose.ui.graphics.ColorFilter
|
|||
import androidx.compose.ui.graphics.ColorMatrix
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import com.pixelized.rplexicon.R
|
||||
|
||||
|
||||
@Composable
|
||||
fun BackgroundImage(
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color = LocalContentColor.current,
|
||||
background: Brush = rememberBackgroundGradient(),
|
||||
painter: Painter,
|
||||
) {
|
||||
Box(
|
||||
|
|
@ -36,7 +36,7 @@ fun BackgroundImage(
|
|||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.background(brush = rememberBackgroundGradient())
|
||||
.background(brush = background)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@ fun BackgroundImage(
|
|||
)
|
||||
},
|
||||
model: Any?,
|
||||
background: Brush = rememberBackgroundGradient(),
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
|
|
@ -66,19 +67,22 @@ fun BackgroundImage(
|
|||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.background(brush = rememberBackgroundGradient())
|
||||
.background(brush = background)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberBackgroundGradient(): Brush {
|
||||
fun rememberBackgroundGradient(
|
||||
from: Float = 0.5f,
|
||||
to: Float = 1.0f,
|
||||
): Brush {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
return remember {
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
colorScheme.surface.copy(alpha = 0.5f),
|
||||
colorScheme.surface.copy(alpha = 1.0f),
|
||||
colorScheme.surface.copy(alpha = from),
|
||||
colorScheme.surface.copy(alpha = to),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
package com.pixelized.rplexicon.ui.composable
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.animation.animateColor
|
||||
import androidx.compose.animation.core.animateDp
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
|
||||
@Composable
|
||||
fun IndicatorStep(
|
||||
modifier: Modifier = Modifier,
|
||||
count: Int,
|
||||
selectedIndex: Int?,
|
||||
defaultSize: Dp = 4.dp,
|
||||
selectedWidth: Dp = 16.dp,
|
||||
indicatorSpacing: Dp = 4.dp,
|
||||
) {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val defaultColor = remember { colorScheme.onSurface.copy(alpha = 0.35f) }
|
||||
val selectedColor = remember { colorScheme.primary }
|
||||
|
||||
Row(modifier = modifier) {
|
||||
repeat(count) { index ->
|
||||
val transition = rememberIndicatorTransition(
|
||||
selected = selectedIndex == index,
|
||||
defaultSize = defaultSize,
|
||||
selectedWidth = selectedWidth,
|
||||
defaultColor = defaultColor,
|
||||
selectedColor = selectedColor,
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(size = transition.size)
|
||||
.background(color = transition.color, shape = CircleShape)
|
||||
)
|
||||
if (index != count - 1) {
|
||||
Spacer(modifier = Modifier.width(indicatorSpacing))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberIndicatorTransition(
|
||||
selected: Boolean,
|
||||
defaultSize: Dp,
|
||||
selectedWidth: Dp,
|
||||
defaultColor: Color,
|
||||
selectedColor: Color,
|
||||
): IndicatorStyle {
|
||||
val transition = updateTransition(
|
||||
label = "IndicatorStep selection transition",
|
||||
targetState = selected
|
||||
)
|
||||
val color = transition.animateColor(
|
||||
label = "IndicatorStep background animation",
|
||||
targetValueByState = {
|
||||
when (it) {
|
||||
true -> selectedColor
|
||||
else -> defaultColor
|
||||
}
|
||||
}
|
||||
)
|
||||
val width by transition.animateDp(
|
||||
label = "IndicatorStep size animation",
|
||||
targetValueByState = {
|
||||
when (it) {
|
||||
true -> selectedWidth
|
||||
else -> defaultSize
|
||||
}
|
||||
}
|
||||
)
|
||||
return remember {
|
||||
IndicatorStyle(
|
||||
color = color,
|
||||
size = derivedStateOf {
|
||||
DpSize(width = width, height = defaultSize)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class IndicatorStyle(
|
||||
color: State<Color>,
|
||||
size: State<DpSize>,
|
||||
) {
|
||||
val color: Color by color
|
||||
val size: DpSize by size
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
fun IndicatorStepPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
IndicatorStep(
|
||||
modifier = Modifier.padding(all = 4.dp),
|
||||
count = 3,
|
||||
selectedIndex = 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ package com.pixelized.rplexicon.ui.screens.character
|
|||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
|
@ -33,13 +32,17 @@ import androidx.compose.material.ripple.rememberRipple
|
|||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ScrollableTabRow
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.minimumInteractiveComponentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -47,6 +50,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -57,7 +61,6 @@ import com.pixelized.rplexicon.LocalRollOverlay
|
|||
import com.pixelized.rplexicon.LocalSnack
|
||||
import com.pixelized.rplexicon.NO_WINDOW_INSETS
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.IndicatorStep
|
||||
import com.pixelized.rplexicon.ui.composable.Loader
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.ProficiencyUio.ID.*
|
||||
|
|
@ -71,6 +74,9 @@ import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationP
|
|||
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.chooser.SpellLevelChooser
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.chooser.SpellLevelChooserPreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.inventory.InventoryPage
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.inventory.InventoryPagePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.inventory.InventoryViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.proficiency.ProficiencyPage
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.proficiency.ProficiencyPreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.proficiency.ProficiencyViewModel
|
||||
|
|
@ -84,6 +90,7 @@ import kotlinx.coroutines.launch
|
|||
@Composable
|
||||
fun CharacterSheetScreen(
|
||||
viewModel: CharacterSheetViewModel = hiltViewModel(),
|
||||
inventoryViewModel: InventoryViewModel = hiltViewModel(),
|
||||
proficiencyViewModel: ProficiencyViewModel = hiltViewModel(),
|
||||
attacksViewModel: AttacksViewModel = hiltViewModel(),
|
||||
spellsViewModel: SpellsViewModel = hiltViewModel(),
|
||||
|
|
@ -106,7 +113,8 @@ fun CharacterSheetScreen(
|
|||
val haveAction = attacksViewModel.attacks.value.isNotEmpty()
|
||||
val haveSpell = spellsViewModel.spells.value.isNotEmpty()
|
||||
val haveAlteration = alterationsViewModel.alterations.value.isNotEmpty()
|
||||
haveSheet.toInt() + (haveAction || haveSpell).toInt() + haveAlteration.toInt()
|
||||
val haveInventory = true
|
||||
haveSheet.toInt() + (haveAction || haveSpell).toInt() + haveAlteration.toInt() + haveInventory.toInt()
|
||||
}
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
|
@ -126,14 +134,8 @@ fun CharacterSheetScreen(
|
|||
onBack = {
|
||||
screen.popBackStack()
|
||||
},
|
||||
indicator = {
|
||||
IndicatorStep(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.BottomCenter)
|
||||
.padding(all = 4.dp),
|
||||
count = pagerState.pageCount,
|
||||
selectedIndex = pagerState.currentPage,
|
||||
)
|
||||
onTab = {
|
||||
scope.launch { pagerState.animateScrollToPage(it) }
|
||||
},
|
||||
loader = {
|
||||
Loader(
|
||||
|
|
@ -159,6 +161,11 @@ fun CharacterSheetScreen(
|
|||
viewModel = alterationsViewModel,
|
||||
)
|
||||
},
|
||||
inventory = {
|
||||
InventoryPage(
|
||||
viewModel = inventoryViewModel,
|
||||
)
|
||||
},
|
||||
sheet = {
|
||||
SpellLevelChooser(
|
||||
modifier = Modifier.navigationBarsPadding(),
|
||||
|
|
@ -205,11 +212,12 @@ private fun CharacterSheetContent(
|
|||
onFullRefresh: () -> Unit,
|
||||
name: String,
|
||||
onBack: () -> Unit,
|
||||
onTab: (Int) -> Unit,
|
||||
loader: @Composable BoxScope.() -> Unit,
|
||||
proficiencies: @Composable PagerScope.() -> Unit,
|
||||
actions: @Composable PagerScope.() -> Unit,
|
||||
alterations: @Composable PagerScope.() -> Unit,
|
||||
indicator: @Composable BoxScope.() -> Unit,
|
||||
inventory: @Composable PagerScope.() -> Unit,
|
||||
sheet: @Composable () -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
|
|
@ -263,33 +271,34 @@ private fun CharacterSheetContent(
|
|||
}
|
||||
},
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier.navigationBarsPadding(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding(),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
) {
|
||||
Column {
|
||||
PagerHeader(
|
||||
pagerState = pagerState,
|
||||
onTab = onTab,
|
||||
)
|
||||
HorizontalPager(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.pullRefresh(refreshState),
|
||||
state = pagerState,
|
||||
beyondBoundsPageCount = 2,
|
||||
beyondBoundsPageCount = 0,
|
||||
verticalAlignment = Alignment.Top,
|
||||
pageContent = { page ->
|
||||
when (page) {
|
||||
0 -> proficiencies()
|
||||
1 -> actions()
|
||||
2 -> alterations()
|
||||
0 -> inventory()
|
||||
1 -> proficiencies()
|
||||
2 -> actions()
|
||||
3 -> alterations()
|
||||
}
|
||||
}
|
||||
)
|
||||
loader()
|
||||
indicator()
|
||||
}
|
||||
loader()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -298,6 +307,45 @@ private fun CharacterSheetContent(
|
|||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun PagerHeader(
|
||||
pagerState: PagerState,
|
||||
tabs: List<String> = headers(),
|
||||
onTab: (Int) -> Unit,
|
||||
) {
|
||||
ScrollableTabRow(
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
) {
|
||||
tabs.forEachIndexed { index, tab ->
|
||||
Tab(
|
||||
selected = pagerState.currentPage == index,
|
||||
selectedContentColor = MaterialTheme.colorScheme.onSurface,
|
||||
unselectedContentColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f),
|
||||
onClick = { onTab(index) },
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
text = tab,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
private fun headers(): List<String> {
|
||||
val inventory = stringResource(id = R.string.character_sheet_tab_inventory)
|
||||
val proficiency = stringResource(id = R.string.character_sheet_tab_proficiency)
|
||||
val actions = stringResource(id = R.string.character_sheet_tab_actions)
|
||||
val alteration = stringResource(id = R.string.character_sheet_tab_alteration)
|
||||
return remember {
|
||||
listOf(inventory, proficiency, actions, alteration)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
|
|
@ -320,21 +368,14 @@ private fun CharacterScreenPreview(
|
|||
refreshState = rememberPullRefreshState(refreshing = false, onRefresh = { }),
|
||||
name = "Brulkhai",
|
||||
onBack = { },
|
||||
onTab = { },
|
||||
onRefresh = { },
|
||||
onFullRefresh = { },
|
||||
loader = { },
|
||||
proficiencies = { ProficiencyPreview() },
|
||||
actions = { ActionPagePreview() },
|
||||
alterations = { AlterationPagePreview() },
|
||||
indicator = {
|
||||
IndicatorStep(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.BottomCenter)
|
||||
.padding(all = 4.dp),
|
||||
count = 3,
|
||||
selectedIndex = 0,
|
||||
)
|
||||
},
|
||||
inventory = { InventoryPagePreview() },
|
||||
sheet = { SpellLevelChooserPreview() },
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||
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.repository.data.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.EquipmentRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.InventoryRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -29,6 +31,8 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
private val characterRepository: CharacterSheetRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val inventoryRepository: InventoryRepository,
|
||||
private val equipmentRepository: EquipmentRepository,
|
||||
private val actionRepository: ActionRepository,
|
||||
private val spellRepository: SpellRepository,
|
||||
private val skillRepository: SkillRepository,
|
||||
|
|
@ -80,7 +84,29 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
Log.e(TAG, exception.message, exception)
|
||||
}
|
||||
}
|
||||
awaitAll(characters, description)
|
||||
val inventory = async {
|
||||
try {
|
||||
if (force || inventoryRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||
inventoryRepository.fetchInventory()
|
||||
} else {
|
||||
Unit
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message, exception)
|
||||
}
|
||||
}
|
||||
val equipment = async {
|
||||
try {
|
||||
if (force || equipmentRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||
equipmentRepository.fetchEquipment()
|
||||
} else {
|
||||
Unit
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message, exception)
|
||||
}
|
||||
}
|
||||
awaitAll(characters)
|
||||
val alterations = async {
|
||||
try {
|
||||
if (force || alterationRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||
|
|
@ -95,7 +121,7 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
val actions = async {
|
||||
try {
|
||||
if (force || actionRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||
actionRepository.fetchActions()
|
||||
actionRepository.fetchActions(characters = characterRepository.data.value)
|
||||
} else {
|
||||
Unit
|
||||
}
|
||||
|
|
@ -125,7 +151,7 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
Log.e(TAG, exception.message, exception)
|
||||
}
|
||||
}
|
||||
awaitAll(alterations, actions, spells, skill)
|
||||
awaitAll(description, alterations, inventory, equipment, actions, spells, skill)
|
||||
_isLoading.value = false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
|
||||
|
||||
@Composable
|
||||
fun AttackHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
padding: PaddingValues = PaddingValues(horizontal = 16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(paddingValues = padding),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(id = R.string.character_sheet_title_attacks).let {
|
||||
AnnotatedString(
|
||||
text = it,
|
||||
spanStyles = listOf(
|
||||
AnnotatedString.Range(
|
||||
item = MaterialTheme.lexicon.typography.bodyDropCapSpan,
|
||||
start = 0,
|
||||
end = Integer.min(1, it.length),
|
||||
)
|
||||
)
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
Divider(
|
||||
modifier = Modifier.padding(paddingValues = padding),
|
||||
color = MaterialTheme.lexicon.colorScheme.placeholder,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun AttackHeaderPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
SkillHeader()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.BackgroundImage
|
||||
import com.pixelized.rplexicon.ui.composable.rememberBackgroundGradient
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
@Stable
|
||||
data class EquipmentItemUio(
|
||||
@DrawableRes val silhouette: Int,
|
||||
val head: String? = null,
|
||||
val face: String? = null,
|
||||
val shoulder: String? = null,
|
||||
val neck: String? = null,
|
||||
val body: String? = null,
|
||||
val chest: String? = null,
|
||||
val arm: String? = null,
|
||||
val waist: String? = null,
|
||||
val hands: String? = null,
|
||||
val ringRight: String? = null,
|
||||
val foot: String? = null,
|
||||
val ringLeft: String? = null,
|
||||
val mainHand: String? = null,
|
||||
val offHand: String? = null,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun EquipmentItem(
|
||||
modifier: Modifier = Modifier,
|
||||
equipments: EquipmentItemUio,
|
||||
onClick: (String) -> Unit,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
BackgroundImage(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
background = rememberBackgroundGradient(from = 0.75f, to = 0.95f),
|
||||
painter = painterResource(id = R.drawable.ic_woman_archer_256),
|
||||
)
|
||||
|
||||
Column {
|
||||
Row {
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Ltr,
|
||||
icon = R.drawable.ic_visored_helm_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_head),
|
||||
item = equipments.head,
|
||||
onClick = onClick,
|
||||
)
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Rtl,
|
||||
icon = R.drawable.ic_double_face_mask_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_face),
|
||||
item = equipments.face,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
Row {
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Ltr,
|
||||
icon = R.drawable.ic_cape_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_shoulder),
|
||||
item = equipments.shoulder,
|
||||
onClick = onClick,
|
||||
)
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Rtl,
|
||||
icon = R.drawable.ic_gem_chain_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_neck),
|
||||
item = equipments.neck,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
Row {
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Ltr,
|
||||
icon = R.drawable.ic_lamellar_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_body),
|
||||
item = equipments.body,
|
||||
onClick = onClick,
|
||||
)
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Rtl,
|
||||
icon = R.drawable.ic_leather_armor_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_chest),
|
||||
item = equipments.chest,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
Row {
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Ltr,
|
||||
icon = R.drawable.ic_bracer_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_arm),
|
||||
item = equipments.arm,
|
||||
onClick = onClick,
|
||||
)
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Rtl,
|
||||
icon = R.drawable.ic_belt_armor_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_waist),
|
||||
item = equipments.waist,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
Row {
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Ltr,
|
||||
icon = R.drawable.ic_gauntlet_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_hands),
|
||||
item = equipments.hands,
|
||||
onClick = onClick,
|
||||
)
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Rtl,
|
||||
icon = R.drawable.ic_ring_1_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_ring_right),
|
||||
item = equipments.ringRight,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
Row {
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Ltr,
|
||||
icon = R.drawable.ic_boots_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_foot),
|
||||
item = equipments.foot,
|
||||
onClick = onClick,
|
||||
)
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Rtl,
|
||||
icon = R.drawable.ic_ring_2_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_ring_left),
|
||||
item = equipments.ringLeft,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
Row {
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Ltr,
|
||||
icon = R.drawable.ic_sword_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_main_hand),
|
||||
item = equipments.mainHand,
|
||||
onClick = onClick,
|
||||
)
|
||||
EquipmentItemContent(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
direction = LayoutDirection.Rtl,
|
||||
icon = R.drawable.ic_shield_24,
|
||||
label = stringResource(id = R.string.character_sheet_equipment_off_hand),
|
||||
item = equipments.offHand,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EquipmentItemContent(
|
||||
modifier: Modifier = Modifier,
|
||||
direction: LayoutDirection,
|
||||
padding: PaddingValues = PaddingValues(start = 16.dp, top = 4.dp, bottom = 4.dp),
|
||||
@DrawableRes icon: Int,
|
||||
label: String,
|
||||
item: String? = null,
|
||||
onClick: (String) -> Unit,
|
||||
) {
|
||||
EquipmentItemLayout(
|
||||
modifier = Modifier
|
||||
.clickable(enabled = item != null) { item?.let(onClick) }
|
||||
.padding(paddingValues = padding)
|
||||
.then(other = modifier),
|
||||
direction = direction,
|
||||
icon = {
|
||||
Icon(
|
||||
modifier = Modifier.size(size = 32.dp),
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
Text(
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontStyle = FontStyle.Italic,
|
||||
fontWeight = FontWeight.Light,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
text = label,
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
text = item ?: "",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EquipmentItemLayout(
|
||||
modifier: Modifier = Modifier,
|
||||
direction: LayoutDirection,
|
||||
icon: @Composable RowScope.() -> Unit,
|
||||
text: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalLayoutDirection provides direction,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
) {
|
||||
icon()
|
||||
text()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun InventoryItemPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
EquipmentItem(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
equipments = EquipmentItemUio(
|
||||
silhouette = R.drawable.ic_woman_archer_256,
|
||||
shoulder = "Cloak of Protection",
|
||||
mainHand = "Battleaxe",
|
||||
offHand = "Shield",
|
||||
),
|
||||
onClick = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
|||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
|
@ -24,9 +25,10 @@ import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
|||
|
||||
|
||||
@Composable
|
||||
fun AlterationHeader(
|
||||
fun GenericHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
padding: PaddingValues = PaddingValues(horizontal = 16.dp),
|
||||
@StringRes label: Int,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
|
|
@ -40,7 +42,7 @@ fun AlterationHeader(
|
|||
fontWeight = FontWeight.Bold,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(id = R.string.character_sheet_title_alteration).let {
|
||||
text = stringResource(id = label).let {
|
||||
AnnotatedString(
|
||||
text = it,
|
||||
spanStyles = listOf(
|
||||
|
|
@ -65,10 +67,12 @@ fun AlterationHeader(
|
|||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun AlterationPreview() {
|
||||
private fun GenericHeaderPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
AlterationHeader()
|
||||
GenericHeader(
|
||||
label = R.string.character_sheet_title_inventory
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
@Stable
|
||||
data class InventoryItemUio(
|
||||
val name: String,
|
||||
val amount: String? = null,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun InventoryItem(
|
||||
modifier: Modifier = Modifier,
|
||||
padding: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 2.dp),
|
||||
item: InventoryItemUio,
|
||||
) {
|
||||
FlowRow(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues = padding)
|
||||
.then(other = modifier),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Bold,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = item.name,
|
||||
)
|
||||
item.amount?.let {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Medium,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
text = " : ",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Light,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = it
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun InventoryItemPreview(
|
||||
@PreviewParameter(InventoryItemPreviewProvider::class) preview: InventoryItemUio,
|
||||
) {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
InventoryItem(item = preview)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class InventoryItemPreviewProvider : PreviewParameterProvider<InventoryItemUio> {
|
||||
override val values: Sequence<InventoryItemUio> = sequenceOf(
|
||||
InventoryItemUio(
|
||||
name = "- Cordes",
|
||||
amount = "15 mètres",
|
||||
),
|
||||
InventoryItemUio(
|
||||
name = "- Piège de chasse",
|
||||
amount = null,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
|
||||
|
||||
@Composable
|
||||
fun SkillHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
padding: PaddingValues = PaddingValues(horizontal = 16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(paddingValues = padding),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(id = R.string.character_sheet_title_skills).let {
|
||||
AnnotatedString(
|
||||
text = it,
|
||||
spanStyles = listOf(
|
||||
AnnotatedString.Range(
|
||||
item = MaterialTheme.lexicon.typography.bodyDropCapSpan,
|
||||
start = 0,
|
||||
end = Integer.min(1, it.length),
|
||||
)
|
||||
)
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
Divider(
|
||||
modifier = Modifier.padding(paddingValues = padding),
|
||||
color = MaterialTheme.lexicon.colorScheme.placeholder,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun SkillHeaderPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
SkillHeader()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.preview
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.EquipmentItemUio
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberEquipmentState(): State<EquipmentItemUio> {
|
||||
return remember {
|
||||
mutableStateOf(
|
||||
EquipmentItemUio(
|
||||
silhouette = R.drawable.ic_woman_archer_256,
|
||||
shoulder = "Cloak of Protection",
|
||||
mainHand = "Battleaxe",
|
||||
offHand = "Shield",
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.preview
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.EquipmentItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItemUio
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberInventoryListState(): State<List<InventoryItemUio>> {
|
||||
return remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
InventoryItemUio(name = "Bourse"),
|
||||
InventoryItemUio(name = "- Or", amount = "21"),
|
||||
InventoryItemUio(name = "Sac à dos"),
|
||||
InventoryItemUio(name = "- Sac de couchage"),
|
||||
InventoryItemUio(name = "- Kit de cuisine"),
|
||||
InventoryItemUio(name = "- Boite d'allume-feu"),
|
||||
InventoryItemUio(name = "- Torches", amount = "10"),
|
||||
InventoryItemUio(name = "- Rations journalières", amount = "10"),
|
||||
InventoryItemUio(name = "- Outre d'eau"),
|
||||
InventoryItemUio(name = "- Cordes", amount = "15 mètres"),
|
||||
InventoryItemUio(name = "- Piège de chasse"),
|
||||
InventoryItemUio(name = "- Bâton de marche"),
|
||||
InventoryItemUio(name = "Dague"),
|
||||
InventoryItemUio(name = "Javelot", amount = "4"),
|
||||
InventoryItemUio(name = "Cape de protection"),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package com.pixelized.rplexicon.ui.screens.character.factory
|
|||
import com.pixelized.rplexicon.model.AssignedSpell
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.icon
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@ import androidx.compose.ui.window.Dialog
|
|||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.LocalRollOverlay
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.edit.HandleHitPointEditDialog
|
||||
import com.pixelized.rplexicon.ui.composable.edit.HandleSkillEditDialog
|
||||
import com.pixelized.rplexicon.ui.composable.edit.HandleSpellEditDialog
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToSpellDetail
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.Attack
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AttackHeader
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AttackUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillHeader
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.GenericHeader
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItem
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.Spell
|
||||
|
|
@ -179,7 +179,9 @@ fun ActionsPageContent(
|
|||
) {
|
||||
if (attacks.value.isNotEmpty()) {
|
||||
stickyHeader {
|
||||
AttackHeader()
|
||||
GenericHeader(
|
||||
label = R.string.character_sheet_title_attacks,
|
||||
)
|
||||
}
|
||||
items(items = attacks.value) {
|
||||
Attack(
|
||||
|
|
@ -195,7 +197,9 @@ fun ActionsPageContent(
|
|||
|
||||
if (tokens.value.isNotEmpty()) {
|
||||
stickyHeader {
|
||||
SkillHeader()
|
||||
GenericHeader(
|
||||
label = R.string.character_sheet_title_skills,
|
||||
)
|
||||
}
|
||||
items(items = tokens.value) {
|
||||
SkillItem(
|
||||
|
|
@ -234,24 +238,6 @@ fun ActionsPageContent(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HandleSkillDetailDialog(
|
||||
dialog: State<SkillDetailUio?>,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
dialog.value?.let {
|
||||
Dialog(
|
||||
properties = remember { DialogProperties(usePlatformDefaultWidth = false) },
|
||||
onDismissRequest = onDismissRequest,
|
||||
) {
|
||||
SkillDetail(
|
||||
detail = it,
|
||||
onClose = onDismissRequest,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.pixelized.rplexicon.model.Attack
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AttackUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.factory.AttackUioFactory
|
||||
|
|
@ -38,25 +38,22 @@ class AttacksViewModel @Inject constructor(
|
|||
val attacks: State<List<AttackUio>> get() = _attacks
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
launch {
|
||||
actionRepository.data
|
||||
.combine(alterationRepository.assignedAlterations) { actions, _ -> actions }
|
||||
.collect { sheets ->
|
||||
_attacks.value = withContext(Dispatchers.Default) {
|
||||
val alterations = alterationRepository.getActiveAlterationsStatus(
|
||||
character = character,
|
||||
)
|
||||
sheets[character]?.map { action ->
|
||||
attackFactory.convert(
|
||||
characterSheet = model,
|
||||
alterations = alterations,
|
||||
attack = action,
|
||||
)
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
actionRepository.data
|
||||
.combine(alterationRepository.assignedAlterations) { actions, _ -> actions }
|
||||
.collect { sheets ->
|
||||
val alterations = alterationRepository.getActiveAlterationsStatus(
|
||||
character = character,
|
||||
)
|
||||
val attacks = sheets[character]?.map { action ->
|
||||
attackFactory.convert(
|
||||
characterSheet = model,
|
||||
alterations = alterations,
|
||||
attack = action,
|
||||
)
|
||||
} ?: emptyList()
|
||||
withContext(Dispatchers.Main) { _attacks.value = attacks }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.ui.composable.edit.HpPointDialogUio
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.CharacterSheetHeaderUio
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import androidx.compose.material3.Surface
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -30,6 +31,8 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
|
|
@ -123,6 +126,24 @@ fun SkillDetail(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HandleSkillDetailDialog(
|
||||
dialog: State<SkillDetailUio?>,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
dialog.value?.let {
|
||||
Dialog(
|
||||
properties = remember { DialogProperties(usePlatformDefaultWidth = false) },
|
||||
onDismissRequest = onDismissRequest,
|
||||
) {
|
||||
SkillDetail(
|
||||
detail = it,
|
||||
onClose = onDismissRequest,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ import com.pixelized.rplexicon.model.DiceThrow
|
|||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.model.Skill
|
||||
import com.pixelized.rplexicon.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.ui.composable.edit.SkillEditDialogUio
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import com.pixelized.rplexicon.model.DiceThrow
|
|||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.model.Throw
|
||||
import com.pixelized.rplexicon.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.composable.edit.SpellEditDialogUio
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellHeaderUio
|
||||
|
|
@ -60,80 +60,77 @@ class SpellsViewModel @Inject constructor(
|
|||
|
||||
init {
|
||||
// TODO rework that part. use factory
|
||||
viewModelScope.launch {
|
||||
launch(Dispatchers.IO) {
|
||||
characterRepository.data
|
||||
.combine(spellRepository.spells) { sheets, spells ->
|
||||
character = sheets.getValue(characterName)
|
||||
Struct(sheets = sheets, spells = spells)
|
||||
}
|
||||
.combine(firebaseRepository.getCharacter(character = characterName)) { struct, fire ->
|
||||
characterFire = fire
|
||||
struct.also { it.fire = fire }
|
||||
}
|
||||
.collect { data ->
|
||||
val spells = data.spells[characterName]
|
||||
val character = data.sheets.getValue(characterName)
|
||||
_spells.value = withContext(Dispatchers.Default) {
|
||||
if (character.isWarlock) {
|
||||
spells
|
||||
?.sortedBy { it.spell.name }
|
||||
?.sortedBy { it.spell.level }
|
||||
?.groupBy { it.spell.level == 0 }
|
||||
?.map { entry ->
|
||||
if (entry.key) {
|
||||
SpellHeaderUio(
|
||||
level = 0,
|
||||
count = null,
|
||||
)
|
||||
} else {
|
||||
val firstSpellSlot = character.firstSpellSlot()
|
||||
SpellHeaderUio(
|
||||
level = firstSpellSlot ?: 1,
|
||||
count = character.spell(level = firstSpellSlot ?: 1)
|
||||
?.let { max ->
|
||||
SpellHeaderUio.Count(
|
||||
value = data.fire.spell(
|
||||
level = firstSpellSlot ?: 1
|
||||
) ?: 0,
|
||||
max = max
|
||||
)
|
||||
}
|
||||
)
|
||||
} to entry.value.map {
|
||||
spellFactory.toUio(
|
||||
assignedSpell = it,
|
||||
characterSheet = character
|
||||
)
|
||||
}
|
||||
}
|
||||
?: emptyList()
|
||||
} else {
|
||||
spells
|
||||
?.sortedBy { it.spell.name }
|
||||
?.sortedBy { it.spell.level }
|
||||
?.groupBy { it.spell.level }
|
||||
?.map { entry ->
|
||||
SpellHeaderUio(
|
||||
level = entry.key,
|
||||
count = character.spell(level = entry.key)?.let { max ->
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
characterRepository.data
|
||||
.combine(spellRepository.spells) { sheets, spells ->
|
||||
character = sheets.getValue(characterName)
|
||||
Struct(sheets = sheets, spells = spells)
|
||||
}
|
||||
.combine(firebaseRepository.getCharacter(character = characterName)) { struct, fire ->
|
||||
characterFire = fire
|
||||
struct.also { it.fire = fire }
|
||||
}
|
||||
.collect { data ->
|
||||
val spellsBook = data.spells[characterName]
|
||||
val character = data.sheets.getValue(characterName)
|
||||
val spells = if (character.isWarlock) {
|
||||
spellsBook
|
||||
?.sortedBy { it.spell.name }
|
||||
?.sortedBy { it.spell.level }
|
||||
?.groupBy { it.spell.level == 0 }
|
||||
?.map { entry ->
|
||||
if (entry.key) {
|
||||
SpellHeaderUio(
|
||||
level = 0,
|
||||
count = null,
|
||||
)
|
||||
} else {
|
||||
val firstSpellSlot = character.firstSpellSlot()
|
||||
SpellHeaderUio(
|
||||
level = firstSpellSlot ?: 1,
|
||||
count = character.spell(level = firstSpellSlot ?: 1)
|
||||
?.let { max ->
|
||||
SpellHeaderUio.Count(
|
||||
value = data.fire.spell(level = entry.key) ?: 0,
|
||||
value = data.fire.spell(
|
||||
level = firstSpellSlot ?: 1
|
||||
) ?: 0,
|
||||
max = max
|
||||
)
|
||||
},
|
||||
) to entry.value.map {
|
||||
spellFactory.toUio(
|
||||
assignedSpell = it,
|
||||
characterSheet = character
|
||||
)
|
||||
}
|
||||
}
|
||||
?: emptyList()
|
||||
}
|
||||
)
|
||||
} to entry.value.map {
|
||||
spellFactory.toUio(
|
||||
assignedSpell = it,
|
||||
characterSheet = character
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
?: emptyList()
|
||||
} else {
|
||||
spellsBook
|
||||
?.sortedBy { it.spell.name }
|
||||
?.sortedBy { it.spell.level }
|
||||
?.groupBy { it.spell.level }
|
||||
?.map { entry ->
|
||||
SpellHeaderUio(
|
||||
level = entry.key,
|
||||
count = character.spell(level = entry.key)?.let { max ->
|
||||
SpellHeaderUio.Count(
|
||||
value = data.fire.spell(level = entry.key) ?: 0,
|
||||
max = max
|
||||
)
|
||||
},
|
||||
) to entry.value.map {
|
||||
spellFactory.toUio(
|
||||
assignedSpell = it,
|
||||
characterSheet = character
|
||||
)
|
||||
}
|
||||
}
|
||||
?: emptyList()
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) { _spells.value = spells }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationHeader
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItem
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.GenericHeader
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.preview.rememberRollAlterations
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -64,9 +65,6 @@ fun AlterationPageContent(
|
|||
modifier = modifier,
|
||||
contentPadding = PaddingValues(top = 8.dp, bottom = 16.dp),
|
||||
) {
|
||||
stickyHeader {
|
||||
AlterationHeader()
|
||||
}
|
||||
items(items = alterations.value) {
|
||||
AlterationItem(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.pages.inventory
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.LocalSnack
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.EquipmentItem
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.EquipmentItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.GenericHeader
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItem
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberEquipmentState
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberInventoryListState
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.HandleSkillDetailDialog
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun InventoryPage(
|
||||
viewModel: InventoryViewModel,
|
||||
) {
|
||||
val snack = LocalSnack.current
|
||||
val snackJob = remember { mutableStateOf<Job?>(null) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
InventoryPageContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
equipments = viewModel.equipments,
|
||||
inventory = viewModel.inventory,
|
||||
onEquipment = {
|
||||
snackJob.value?.cancel()
|
||||
viewModel.showSkillDetailDialog(item = it)
|
||||
},
|
||||
)
|
||||
|
||||
HandleSkillDetailDialog(
|
||||
dialog = viewModel.dialog,
|
||||
onDismissRequest = viewModel::hideSkillDetailDialog,
|
||||
)
|
||||
|
||||
LaunchedEffect(key1 = "InventorySnack") {
|
||||
viewModel.snack.collect { message ->
|
||||
if (message != null) {
|
||||
snackJob.value?.cancel()
|
||||
snackJob.value = scope.launch { snack.showSnackbar(message = message) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun InventoryPageContent(
|
||||
modifier: Modifier = Modifier,
|
||||
equipments: State<EquipmentItemUio?>,
|
||||
inventory: State<List<InventoryItemUio>>,
|
||||
onEquipment: (String) -> Unit,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = PaddingValues(top = 8.dp, bottom = 16.dp),
|
||||
) {
|
||||
equipments.value?.let {
|
||||
item {
|
||||
EquipmentItem(
|
||||
modifier = Modifier.padding(bottom = 16.dp),
|
||||
equipments = it,
|
||||
onClick = onEquipment,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (inventory.value.isNotEmpty()) {
|
||||
stickyHeader {
|
||||
GenericHeader(
|
||||
label = R.string.character_sheet_title_inventory
|
||||
)
|
||||
}
|
||||
items(items = inventory.value) {
|
||||
InventoryItem(
|
||||
modifier = Modifier.padding(
|
||||
top = when (it.name.contains("-")) {
|
||||
true -> 0.dp
|
||||
else -> 4.dp
|
||||
}
|
||||
),
|
||||
item = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
fun InventoryPagePreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
InventoryPageContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
equipments = rememberEquipmentState(),
|
||||
inventory = rememberInventoryListState(),
|
||||
onEquipment = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.pages.inventory
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.EquipmentRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.InventoryRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.EquipmentItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.SkillDetailUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.context
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class InventoryViewModel @Inject constructor(
|
||||
private val inventoryRepository: InventoryRepository,
|
||||
private val equipmentRepository: EquipmentRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
application: Application
|
||||
) : AndroidViewModel(application) {
|
||||
private val character = savedStateHandle.characterSheetArgument.name
|
||||
|
||||
private val _equipments = mutableStateOf<EquipmentItemUio?>(null)
|
||||
val equipments: State<EquipmentItemUio?> get() = _equipments
|
||||
|
||||
private val _inventory = mutableStateOf<List<InventoryItemUio>>(emptyList())
|
||||
val inventory: State<List<InventoryItemUio>> get() = _inventory
|
||||
|
||||
private val _dialog = mutableStateOf<SkillDetailUio?>(null)
|
||||
val dialog: State<SkillDetailUio?> get() = _dialog
|
||||
|
||||
private val _snack = MutableSharedFlow<String?>()
|
||||
val snack: SharedFlow<String?> get() = _snack
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
launch(Dispatchers.IO) {
|
||||
inventoryRepository.data.collect {
|
||||
val items = it[character]?.items?.map { item ->
|
||||
InventoryItemUio(
|
||||
name = item.name,
|
||||
amount = item.amount,
|
||||
)
|
||||
} ?: emptyList()
|
||||
withContext(Dispatchers.Main) {
|
||||
_inventory.value = items
|
||||
}
|
||||
}
|
||||
}
|
||||
launch(Dispatchers.IO) {
|
||||
equipmentRepository.data.collect {
|
||||
val equipments = it[character]?.let { data ->
|
||||
EquipmentItemUio(
|
||||
silhouette = R.drawable.ic_woman_archer_256,
|
||||
head = data.head,
|
||||
face = data.face,
|
||||
shoulder = data.shoulder,
|
||||
neck = data.neck,
|
||||
body = data.body,
|
||||
chest = data.chest,
|
||||
arm = data.arm,
|
||||
waist = data.waist,
|
||||
hands = data.hand,
|
||||
ringRight = data.ring1,
|
||||
foot = data.foot,
|
||||
ringLeft = data.ring2,
|
||||
mainHand = data.mainHand,
|
||||
offHand = data.offHand,
|
||||
)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
_equipments.value = equipments
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showSkillDetailDialog(item: String) {
|
||||
val description = descriptionRepository.find(name = item)
|
||||
|
||||
if (description != null) {
|
||||
_dialog.value = SkillDetailUio(
|
||||
name = item,
|
||||
original = description.original,
|
||||
description = description.description
|
||||
)
|
||||
} else {
|
||||
viewModelScope.launch {
|
||||
_snack.emit(
|
||||
context.getString(R.string.character_sheet_equipment_empty_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hideSkillDetailDialog() {
|
||||
_dialog.value = null
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.ProficiencyUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio
|
||||
|
|
@ -34,21 +34,19 @@ class ProficiencyViewModel @Inject constructor(
|
|||
val sheet: State<CharacterSheetUio?> get() = _sheet
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
launch {
|
||||
characterRepository.data
|
||||
.combine(alterationRepository.assignedAlterations) { sheets, _ -> sheets }
|
||||
.collect {
|
||||
_sheet.value = withContext(Dispatchers.Default) {
|
||||
val alterations =
|
||||
alterationRepository.getActiveAlterationsStatus(character)
|
||||
characterSheetFactory.convert(
|
||||
sheet = it.getValue(key = character),
|
||||
alterations = alterations,
|
||||
)
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
characterRepository.data
|
||||
.combine(alterationRepository.assignedAlterations) { sheets, _ -> sheets }
|
||||
.collect {
|
||||
val alterations = alterationRepository.getActiveAlterationsStatus(character)
|
||||
val sheet = characterSheetFactory.convert(
|
||||
sheet = it.getValue(key = character),
|
||||
alterations = alterations,
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
_sheet.value = sheet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import androidx.compose.runtime.State
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.LexiconRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LexiconRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.lexiconDetailArgument
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.LexiconRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LexiconRepository
|
||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.pixelized.rplexicon.R
|
|||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import com.pixelized.rplexicon.model.Lexicon.Gender
|
||||
import com.pixelized.rplexicon.model.Lexicon.Race
|
||||
import com.pixelized.rplexicon.repository.data.LexiconRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LexiconRepository
|
||||
import com.pixelized.rplexicon.ui.composable.form.DropDownFieldUio
|
||||
import com.pixelized.rplexicon.ui.composable.form.TextFieldUio
|
||||
import com.pixelized.rplexicon.utilitary.composable.stringResource
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import com.pixelized.rplexicon.repository.data.LocationRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LocationRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.locationDetailArgument
|
||||
import com.pixelized.rplexicon.utilitary.cells
|
||||
import com.pixelized.rplexicon.utilitary.line
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import androidx.compose.runtime.State
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.repository.data.LocationRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LocationRepository
|
||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import androidx.compose.runtime.State
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.pixelized.rplexicon.repository.data.LexiconRepository
|
||||
import com.pixelized.rplexicon.repository.data.LocationRepository
|
||||
import com.pixelized.rplexicon.repository.data.QuestRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LexiconRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LocationRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.QuestRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.questDetailArgument
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import androidx.compose.runtime.State
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.repository.data.QuestRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.QuestRepository
|
||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.business.DiceThrowUseCase
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationDetailUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ package com.pixelized.rplexicon.ui.screens.rolls.factory
|
|||
import com.pixelized.rplexicon.model.Alteration
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package com.pixelized.rplexicon.ui.screens.rolls.factory
|
|||
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import javax.inject.Inject
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.repository.data.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.spellDetailArgument
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.icon
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue