Rework the character sheet.
This commit is contained in:
parent
bd4de62841
commit
ad4e053f8e
31 changed files with 531 additions and 426 deletions
|
|
@ -1,16 +0,0 @@
|
|||
package com.pixelized.rplexicon.facotry.displayable
|
||||
|
||||
import com.pixelized.rplexicon.model.Action
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.ActionsUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConvertActionIntoDisplayableFactory @Inject constructor() {
|
||||
fun toUio(action: Action): ActionsUio {
|
||||
return ActionsUio(
|
||||
title = action.title,
|
||||
hit = action.hit?.faces?.icon,
|
||||
damage = action.damage?.faces?.icon,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.pixelized.rplexicon.facotry.displayable
|
||||
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.model.Attack
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.WeaponUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConvertAttackIntoDisplayableFactory @Inject constructor() {
|
||||
|
||||
fun toUio(attack: Attack, characterSheet: CharacterSheet): WeaponUio? {
|
||||
val hit = attack.hit?.let { dice ->
|
||||
val modifier = dice.modifier.sumOf {
|
||||
when (it) {
|
||||
Property.PROFICIENCY -> characterSheet.proficiency
|
||||
Property.STRENGTH -> characterSheet.strength.modifier
|
||||
Property.DEXTERITY -> characterSheet.dexterity.modifier
|
||||
Property.CONSTITUTION -> characterSheet.constitution.modifier
|
||||
Property.INTELLIGENCE -> characterSheet.intelligence.modifier
|
||||
Property.WISDOM -> characterSheet.wisdom.modifier
|
||||
Property.CHARISMA -> characterSheet.charisma.modifier
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
WeaponUio.Dice(
|
||||
icon = dice.faces.icon,
|
||||
label = "${dice.amount}d${dice.faces}${if (modifier > 0) "+$modifier" else ""}",
|
||||
)
|
||||
}
|
||||
val damage = attack.damage?.let { dice ->
|
||||
val modifier = dice.modifier.sumOf {
|
||||
when (it) {
|
||||
Property.PROFICIENCY -> characterSheet.proficiency
|
||||
Property.STRENGTH -> characterSheet.strength.modifier
|
||||
Property.DEXTERITY -> characterSheet.dexterity.modifier
|
||||
Property.CONSTITUTION -> characterSheet.constitution.modifier
|
||||
Property.INTELLIGENCE -> characterSheet.intelligence.modifier
|
||||
Property.WISDOM -> characterSheet.wisdom.modifier
|
||||
Property.CHARISMA -> characterSheet.charisma.modifier
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
WeaponUio.Dice(
|
||||
icon = dice.faces.icon,
|
||||
label = "${dice.amount}d${dice.faces}${if (modifier > 0) "+$modifier" else ""}",
|
||||
)
|
||||
}
|
||||
return when (attack.type) {
|
||||
Attack.Type.PHYSICAL_MELEE_ATTACK -> WeaponUio(
|
||||
id = attack,
|
||||
icon = R.drawable.ic_crossed_swords_24,
|
||||
name = attack.title,
|
||||
type = "Attaque de corps à corps",
|
||||
range = "3 mêtres",
|
||||
hit = hit,
|
||||
damage = damage,
|
||||
)
|
||||
|
||||
Attack.Type.PHYSICAL_RANGE_ATTACK -> WeaponUio(
|
||||
id = attack,
|
||||
icon = R.drawable.ic_pocket_bow_24,
|
||||
name = attack.title,
|
||||
type = "Attaque à distance",
|
||||
range = "30 mêtres",
|
||||
hit = hit,
|
||||
damage = damage,
|
||||
)
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import javax.inject.Inject
|
|||
|
||||
class ConvertCounterIntoDisplayableFactory @Inject constructor() {
|
||||
fun toUio(counter: Counter): CounterUio = CounterUio(
|
||||
title = counter.title,
|
||||
title = counter.title ?: "",
|
||||
value = counter.value,
|
||||
max = counter.max,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@ import android.util.Log
|
|||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.facotry.model.roll.DiceParser
|
||||
import com.pixelized.rplexicon.facotry.model.roll.ModifierParser
|
||||
import com.pixelized.rplexicon.model.Action
|
||||
import com.pixelized.rplexicon.model.Attack
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.extentions.checkSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||
import javax.inject.Inject
|
||||
|
||||
class ActionParser @Inject constructor(
|
||||
class AttackParser @Inject constructor(
|
||||
private val diceParser: DiceParser,
|
||||
private val modifierParser: ModifierParser,
|
||||
) {
|
||||
|
|
@ -20,11 +19,16 @@ class ActionParser @Inject constructor(
|
|||
fun parse(
|
||||
value: ValueRange,
|
||||
charactersSheets: Map<String, CharacterSheet>,
|
||||
): Map<String, List<Action>> {
|
||||
): Map<String, List<Attack>> {
|
||||
val sheet = value.values.sheet()
|
||||
|
||||
lateinit var structure: Map<String, Int>
|
||||
|
||||
val actions = hashMapOf<String, MutableList<Action>>()
|
||||
// declare helper method to parse String
|
||||
fun List<*>.parseString(key: String): String? =
|
||||
(getOrNull(structure.getValue(key)) as? String)?.takeIf { it.isNotEmpty() }
|
||||
|
||||
val actions = hashMapOf<String, MutableList<Attack>>()
|
||||
|
||||
sheet?.forEachIndexed { index, row ->
|
||||
when {
|
||||
|
|
@ -35,23 +39,18 @@ class ActionParser @Inject constructor(
|
|||
row is List<*> -> {
|
||||
// Assume that the name is the first column.
|
||||
val characterSheet = charactersSheets[row.getOrNull(0) as? String ?: ""]
|
||||
val title = row.getOrNull(structure.getValue(NAME))?.toString()
|
||||
val title = row.parseString(NAME)
|
||||
if (characterSheet != null && title != null) {
|
||||
val action = Action(
|
||||
val attack = Attack(
|
||||
title = title,
|
||||
type = parseType(
|
||||
value = row.getOrNull(structure.getValue(TYPE))?.toString(),
|
||||
),
|
||||
hit = parseThrows(
|
||||
value = row.getOrNull(structure.getValue(HIT))?.toString(),
|
||||
),
|
||||
damage = parseThrows(
|
||||
value = row.getOrNull(structure.getValue(DAMAGE))?.toString(),
|
||||
),
|
||||
type = parseType(value = row.parseString(TYPE)),
|
||||
range = row.parseString(RANGE),
|
||||
hit = parseThrows(value = row.parseString(HIT)),
|
||||
damage = parseThrows(value = row.parseString(DAMAGE)),
|
||||
)
|
||||
actions
|
||||
.getOrPut(characterSheet.name) { mutableListOf() }
|
||||
.add(action)
|
||||
.add(attack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,19 +59,19 @@ class ActionParser @Inject constructor(
|
|||
return actions
|
||||
}
|
||||
|
||||
private fun parseType(value: String?): Action.Type? = try {
|
||||
Action.Type.values().firstOrNull { it.key == value }
|
||||
private fun parseType(value: String?): Attack.Type? = try {
|
||||
Attack.Type.values().firstOrNull { it.key == value }
|
||||
} catch (exception: Exception) {
|
||||
Log.e("ActionParser", exception.message, exception)
|
||||
null
|
||||
}
|
||||
|
||||
private fun parseThrows(value: String?): Action.Throw? {
|
||||
private fun parseThrows(value: String?): Attack.Throw? {
|
||||
if (value != null) {
|
||||
val dice = diceParser.findAll(value = value).firstOrNull()
|
||||
if (dice != null) {
|
||||
val modifier = modifierParser.findAll(value = value)
|
||||
return Action.Throw(
|
||||
return Attack.Throw(
|
||||
amount = dice.count,
|
||||
faces = dice.faces,
|
||||
modifier = modifier,
|
||||
|
|
@ -84,10 +83,11 @@ class ActionParser @Inject constructor(
|
|||
|
||||
companion object {
|
||||
const val NAME = "Nom"
|
||||
const val TYPE = "type"
|
||||
const val TYPE = "Type"
|
||||
const val RANGE = "Portée"
|
||||
const val HIT = "Touché"
|
||||
const val DAMAGE = "Dommage"
|
||||
|
||||
val COLUMNS get() = listOf("", NAME, TYPE, HIT, DAMAGE)
|
||||
val COLUMNS get() = listOf("", NAME, TYPE, RANGE, HIT, DAMAGE)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.rplexicon.facotry.model
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.facotry.model.alteration.CounterParser
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.extentions.checkSheetStructure
|
||||
|
|
@ -8,7 +9,10 @@ import com.pixelized.rplexicon.utilitary.extentions.sheet
|
|||
import javax.inject.Inject
|
||||
|
||||
|
||||
class CharacterSheetParser @Inject constructor() {
|
||||
class CharacterSheetParser @Inject constructor(
|
||||
private val counterParser: CounterParser,
|
||||
) {
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
fun parse(value: ValueRange): Map<String, CharacterSheet> {
|
||||
|
||||
|
|
@ -43,11 +47,59 @@ class CharacterSheetParser @Inject constructor() {
|
|||
if (name != null) {
|
||||
CharacterSheet(
|
||||
name = name,
|
||||
proficiency = item.parseInt(MASTERY) ?: 2,
|
||||
level = item.parseInt(LEVEL) ?: 2,
|
||||
characterClass = item.parseString(CLASS) ?: "",
|
||||
hitPoint = item.parseString(HIT_POINT) ?: "1",
|
||||
maxHitPoint = item.parseString(MAX_HIT_POINT) ?: "1",
|
||||
lifeDice = item.parseInt(LIFE_DICE) ?: 0,
|
||||
spell1 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_1
|
||||
)
|
||||
),
|
||||
spell2 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_2
|
||||
)
|
||||
),
|
||||
spell3 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_3
|
||||
)
|
||||
),
|
||||
spell4 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_4
|
||||
)
|
||||
),
|
||||
spell5 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_5
|
||||
)
|
||||
),
|
||||
spell6 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_6
|
||||
)
|
||||
),
|
||||
spell7 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_7
|
||||
)
|
||||
),
|
||||
spell8 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_8
|
||||
)
|
||||
),
|
||||
spell9 = counterParser.parseCounter(
|
||||
value = item.parseString(
|
||||
SPELL_LEVEL_9
|
||||
)
|
||||
),
|
||||
armorClass = item.parseString(ARMOR_CLASS) ?: "10",
|
||||
speed = item.parseInt(SPEED) ?: 10,
|
||||
proficiency = item.parseInt(MASTERY) ?: 2,
|
||||
strength = item.parseInt(STRENGTH) ?: 10,
|
||||
dexterity = item.parseInt(DEXTERITY) ?: 10,
|
||||
constitution = item.parseInt(CONSTITUTION) ?: 10,
|
||||
|
|
@ -56,8 +108,10 @@ class CharacterSheetParser @Inject constructor() {
|
|||
charisma = item.parseInt(CHARISMA) ?: 10,
|
||||
strengthSavingThrows = item.parseInt(STRENGTH_SAVING_THROW) ?: 0,
|
||||
dexteritySavingThrows = item.parseInt(DEXTERITY_SAVING_THROW) ?: 0,
|
||||
constitutionSavingThrows = item.parseInt(CONSTITUTION_SAVING_THROW) ?: 0,
|
||||
intelligenceSavingThrows = item.parseInt(INTELLIGENCE_SAVING_THROW) ?: 0,
|
||||
constitutionSavingThrows = item.parseInt(CONSTITUTION_SAVING_THROW)
|
||||
?: 0,
|
||||
intelligenceSavingThrows = item.parseInt(INTELLIGENCE_SAVING_THROW)
|
||||
?: 0,
|
||||
wisdomSavingThrows = item.parseInt(WISDOM_SAVING_THROW) ?: 0,
|
||||
charismaSavingThrows = item.parseInt(CHARISMA_SAVING_THROW) ?: 0,
|
||||
acrobatics = item.parseInt(ACROBATICS) ?: 0,
|
||||
|
|
@ -89,8 +143,20 @@ class CharacterSheetParser @Inject constructor() {
|
|||
|
||||
companion object {
|
||||
private const val NAME = "Nom"
|
||||
private const val LEVEL = "Niveau"
|
||||
private const val CLASS = "Classe"
|
||||
private const val HIT_POINT = "Point de vie"
|
||||
private const val MAX_HIT_POINT = "Point de vie MAX"
|
||||
private const val LIFE_DICE = "Dé de vie"
|
||||
private const val SPELL_LEVEL_1 = "Sort de niveau 1"
|
||||
private const val SPELL_LEVEL_2 = "Sort de niveau 2"
|
||||
private const val SPELL_LEVEL_3 = "Sort de niveau 3"
|
||||
private const val SPELL_LEVEL_4 = "Sort de niveau 4"
|
||||
private const val SPELL_LEVEL_5 = "Sort de niveau 5"
|
||||
private const val SPELL_LEVEL_6 = "Sort de niveau 6"
|
||||
private const val SPELL_LEVEL_7 = "Sort de niveau 7"
|
||||
private const val SPELL_LEVEL_8 = "Sort de niveau 8"
|
||||
private const val SPELL_LEVEL_9 = "Sort de niveau 9"
|
||||
private const val ARMOR_CLASS = "Classe d'armure"
|
||||
private const val SPEED = "Vitesse"
|
||||
private const val MASTERY = "Bonus de maîtrise"
|
||||
|
|
@ -128,8 +194,20 @@ class CharacterSheetParser @Inject constructor() {
|
|||
private val ROWS
|
||||
get() = listOf(
|
||||
NAME,
|
||||
LEVEL,
|
||||
CLASS,
|
||||
HIT_POINT,
|
||||
MAX_HIT_POINT,
|
||||
LIFE_DICE,
|
||||
SPELL_LEVEL_1,
|
||||
SPELL_LEVEL_2,
|
||||
SPELL_LEVEL_3,
|
||||
SPELL_LEVEL_4,
|
||||
SPELL_LEVEL_5,
|
||||
SPELL_LEVEL_6,
|
||||
SPELL_LEVEL_7,
|
||||
SPELL_LEVEL_8,
|
||||
SPELL_LEVEL_9,
|
||||
ARMOR_CLASS,
|
||||
SPEED,
|
||||
MASTERY,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class CounterParser @Inject constructor() {
|
|||
return counters
|
||||
}
|
||||
|
||||
private fun parseCounter(title: String, value: String?): Counter? {
|
||||
fun parseCounter(title: String? = null, value: String?): Counter? {
|
||||
return if (value != null) {
|
||||
COUNTER_REGEX.find(value)?.let {
|
||||
val (actual, max) = it.destructured
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
package com.pixelized.rplexicon.model
|
||||
|
||||
data class Action(
|
||||
data class Attack(
|
||||
val title: String,
|
||||
val type: Type?,
|
||||
val range: String?,
|
||||
val hit: Throw?,
|
||||
val damage: Throw?,
|
||||
) {
|
||||
enum class Type(val key: String) {
|
||||
PHYSICAL_MELEE_ATTACK(Property.PHYSICAL_MELEE_ATTACK.key),
|
||||
PHYSICAL_RANGE_ATTACK(Property.PHYSICAL_RANGE_ATTACK.key),
|
||||
SPELL("Sortilège"),
|
||||
PHYSICAL_MELEE_ATTACK("Mêlée"),
|
||||
PHYSICAL_RANGE_ATTACK("Distance"),
|
||||
}
|
||||
|
||||
class Throw(
|
||||
|
|
@ -2,11 +2,23 @@ package com.pixelized.rplexicon.model
|
|||
|
||||
data class CharacterSheet(
|
||||
val name: String,
|
||||
val hitPoint: String, // Point de vie
|
||||
val maxHitPoint: String,
|
||||
val armorClass: String, // Classe d'armure
|
||||
val speed: Int,
|
||||
val proficiency: Int, // Bonus de maîtrise
|
||||
val level: Int, // Niveau
|
||||
val characterClass: String, // Classe
|
||||
val hitPoint: String, // Point de vie
|
||||
val maxHitPoint: String, // Point de vie MAX
|
||||
val lifeDice: Int, // Dé de vie
|
||||
val spell1: Counter?,
|
||||
val spell2: Counter?,
|
||||
val spell3: Counter?,
|
||||
val spell4: Counter?,
|
||||
val spell5: Counter?,
|
||||
val spell6: Counter?,
|
||||
val spell7: Counter?,
|
||||
val spell8: Counter?,
|
||||
val spell9: Counter?,
|
||||
val armorClass: String, // Classe d'armure
|
||||
val speed: Int, // Vitesse
|
||||
val strength: Int, // Force
|
||||
val dexterity: Int, // Dextérité
|
||||
val constitution: Int, // Constitution
|
||||
|
|
@ -52,5 +64,3 @@ data class CharacterSheet(
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.pixelized.rplexicon.model
|
||||
|
||||
data class Counter(
|
||||
val title: String,
|
||||
val title: String? = null,
|
||||
val value: Int,
|
||||
val max: Int?,
|
||||
)
|
||||
|
|
@ -1,39 +1,32 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
|
||||
import com.pixelized.rplexicon.facotry.model.ActionParser
|
||||
import com.pixelized.rplexicon.model.Action
|
||||
import com.pixelized.rplexicon.facotry.model.AttackParser
|
||||
import com.pixelized.rplexicon.model.Attack
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.ServiceNotReady
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@Singleton
|
||||
class ActionRepository @Inject constructor(
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val actionParser: ActionParser,
|
||||
private val actionParser: AttackParser,
|
||||
) {
|
||||
private val _data = MutableStateFlow<Map<String, List<Action>>>(emptyMap())
|
||||
val data: StateFlow<Map<String, List<Action>>> get() = _data
|
||||
private val _data = MutableStateFlow<Map<String, List<Attack>>>(emptyMap())
|
||||
val data: StateFlow<Map<String, List<Attack>>> get() = _data
|
||||
|
||||
fun find(name: String?): List<Action>? {
|
||||
fun find(name: String?): List<Attack>? {
|
||||
return name?.let { _data.value[it] }
|
||||
}
|
||||
|
||||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchActions() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.ACTIONS)
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.ATTACK)
|
||||
val data = actionParser.parse(
|
||||
value = request.execute(),
|
||||
charactersSheets = characterSheetRepository.data.value
|
||||
|
|
@ -41,9 +34,4 @@ class ActionRepository @Inject constructor(
|
|||
_data.emit(data)
|
||||
}
|
||||
}
|
||||
|
||||
private object Sheet {
|
||||
const val ID = "1fHfzeb8y5u9lEQB1iI-jBEhqu7YSip5sAajXcXK7VJ8"
|
||||
const val ACTIONS = "Actions"
|
||||
}
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ class AlterationRepository @Inject constructor(
|
|||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchAlterationSheet() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.ALTERATION_SHEET)
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.ALTERATION)
|
||||
val data = alterationParser.parse(value = request.execute())
|
||||
_alterations.emit(data)
|
||||
}
|
||||
|
|
@ -56,20 +56,11 @@ class AlterationRepository @Inject constructor(
|
|||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchStatusSheet() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.STATUS_SHEET)
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.STATUS)
|
||||
val status = statusParser.parse(value = request.execute())
|
||||
_status.emit(status)
|
||||
val counter = counterParser.parse(values = request.execute())
|
||||
_counter.emit(counter)
|
||||
}
|
||||
}
|
||||
|
||||
private object Sheet {
|
||||
const val ID = "1fHfzeb8y5u9lEQB1iI-jBEhqu7YSip5sAajXcXK7VJ8"
|
||||
const val ALTERATION_SHEET = "Altérations"
|
||||
const val STATUS_SHEET = "État des personnages"
|
||||
const val STATUS_GID = "1246442302"
|
||||
|
||||
const val SHEET_URL = "https://docs.google.com/spreadsheets/d/${ID}/edit#gid=$STATUS_GID"
|
||||
}
|
||||
}
|
||||
|
|
@ -25,19 +25,13 @@ class CharacterSheetRepository @Inject constructor(
|
|||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchCharacterSheet() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.CHARACTER_SHEET)
|
||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.CHARACTER)
|
||||
val data = characterSheetParser.parse(value = request.execute())
|
||||
_data.emit(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val TAG = "CharacterSheetRepository"
|
||||
}
|
||||
|
||||
private object Sheet {
|
||||
const val ID = "1fHfzeb8y5u9lEQB1iI-jBEhqu7YSip5sAajXcXK7VJ8"
|
||||
const val CHARACTER_SHEET = "Feuille de personnage"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.facotry.model.LexiconParser
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
|
|
@ -26,7 +25,7 @@ class LexiconRepository @Inject constructor(
|
|||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchLexicon() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.LEXICON)
|
||||
val request = sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.LEXICON)
|
||||
val data = lexiconParser.parse(data = request.execute())
|
||||
_data.tryEmit(data)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
|
||||
import com.google.api.services.sheets.v4.Sheets
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.facotry.model.LocationParser
|
||||
import com.pixelized.rplexicon.facotry.model.MarqueeParser
|
||||
|
|
@ -30,10 +29,10 @@ class LocationRepository @Inject constructor(
|
|||
|
||||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchLocation() {
|
||||
googleRepository.fetch { sheet: Sheets.Spreadsheets.Values ->
|
||||
googleRepository.fetch { sheet ->
|
||||
val (map, marquee) = awaitAll(
|
||||
async { sheet.get(Sheet.ID, Sheet.MAP).execute() },
|
||||
async { sheet.get(Sheet.ID, Sheet.MARQUEE).execute() },
|
||||
async { sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.MAP).execute() },
|
||||
async { sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.MARQUEE).execute() },
|
||||
)
|
||||
updateData(map = map, marquee = marquee)
|
||||
}
|
||||
|
|
@ -61,6 +60,7 @@ class LocationRepository @Inject constructor(
|
|||
|
||||
companion object {
|
||||
private const val TAG = "LocationRepository"
|
||||
const val SHEET_URL = "https://docs.google.com/spreadsheets/d/${Sheet.ID}/edit#gid=1985553511"
|
||||
const val SHEET_URL =
|
||||
"https://docs.google.com/spreadsheets/d/${Sheet.Lexicon.ID}/edit#gid=1985553511"
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ class QuestRepository @Inject constructor(
|
|||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchQuests() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.QUEST_JOURNAL)
|
||||
val request = sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.QUEST_JOURNAL)
|
||||
val data = request.execute()
|
||||
updateData(data = data)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,23 @@
|
|||
package com.pixelized.rplexicon.repository.data
|
||||
|
||||
object Sheet {
|
||||
const val ID = "1oL9Nu5y37BPEbKxHre4TN9o8nrgy2JQoON4RRkdAHMs"
|
||||
object Lexicon {
|
||||
const val ID = "1oL9Nu5y37BPEbKxHre4TN9o8nrgy2JQoON4RRkdAHMs"
|
||||
|
||||
const val LEXICON = "Lexique"
|
||||
const val QUEST_JOURNAL = "Journal de quêtes"
|
||||
const val LEXICON = "Lexique"
|
||||
const val QUEST_JOURNAL = "Journal de quêtes"
|
||||
const val MAP = "Lieux"
|
||||
const val MARQUEE = "Points d'intérêt"
|
||||
}
|
||||
|
||||
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 MAGIC_LEXICON = "Lexique magique"
|
||||
const val STATUS = "État des personnages"
|
||||
const val ALTERATION = "Altérations"
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import androidx.compose.animation.AnimatedContent
|
|||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.animation.with
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
|
@ -94,7 +95,7 @@ fun <T> DropDownField(
|
|||
AnimatedContent(
|
||||
modifier = Modifier.size(size = 48.dp),
|
||||
targetState = field.value.value != null,
|
||||
transitionSpec = { fadeIn() with fadeOut() },
|
||||
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
||||
label = "DropDownFieldTrailingIconAnimation",
|
||||
) {
|
||||
when (it) {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ import androidx.compose.foundation.layout.systemBarsPadding
|
|||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
|
|
@ -50,15 +48,15 @@ import com.pixelized.rplexicon.NO_WINDOW_INSETS
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.Loader
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.ActionsUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.CounterUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.LabelPoint
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.LabelPointUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.ProficiencyUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.StatUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.WeaponUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.ActionsPages
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.ProficiencyPage
|
||||
import com.pixelized.rplexicon.ui.screens.character.preview.rememberCharacterSheetPreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.preview.rememberWeaponListStatePreview
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
@ -96,19 +94,13 @@ fun CharacterSheetScreen(
|
|||
.fillMaxSize()
|
||||
.systemBarsPadding(),
|
||||
pagerState = rememberPagerState {
|
||||
if (viewModel.actions.value.isNotEmpty() || viewModel.counter.value.isNotEmpty()) {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
}
|
||||
2 // TODO
|
||||
},
|
||||
refreshing = viewModel.isLoading,
|
||||
refreshState = refresh,
|
||||
onRefresh = { scope.launch { viewModel.update() } },
|
||||
sheet = it,
|
||||
actions = viewModel.actions,
|
||||
counter = viewModel.counter,
|
||||
alterations = viewModel.alterations,
|
||||
weapons = viewModel.weapons,
|
||||
onBack = {
|
||||
screen.popBackStack()
|
||||
},
|
||||
|
|
@ -191,9 +183,7 @@ private fun CharacterSheetContent(
|
|||
refreshing: State<Boolean>,
|
||||
onRefresh: () -> Unit,
|
||||
sheet: CharacterSheetUio,
|
||||
actions: State<List<ActionsUio>>,
|
||||
counter: State<List<CounterUio>>,
|
||||
alterations: State<List<String>>,
|
||||
weapons: State<List<WeaponUio>>,
|
||||
onBack: () -> Unit,
|
||||
onStats: (StatUio) -> Unit,
|
||||
onProficiencies: (ProficiencyUio) -> Unit,
|
||||
|
|
@ -270,7 +260,6 @@ private fun CharacterSheetContent(
|
|||
0 -> ProficiencyPage(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(vertical = 16.dp),
|
||||
sheet = sheet,
|
||||
onInitiative = onInitiative,
|
||||
|
|
@ -281,11 +270,8 @@ private fun CharacterSheetContent(
|
|||
1 -> ActionsPages(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(vertical = 16.dp),
|
||||
actions = actions,
|
||||
counter = counter,
|
||||
alterations = alterations,
|
||||
weapons = weapons,
|
||||
onHit = onHit,
|
||||
onDamage = onDamage,
|
||||
)
|
||||
|
|
@ -317,36 +303,7 @@ private fun CharacterScreenPreview() {
|
|||
refreshing = remember { mutableStateOf(false) },
|
||||
onRefresh = { },
|
||||
sheet = rememberCharacterSheetPreview(),
|
||||
actions = remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
ActionsUio(
|
||||
title = "Battle Axe",
|
||||
hit = R.drawable.ic_d20_24,
|
||||
damage = R.drawable.ic_d8_24,
|
||||
),
|
||||
ActionsUio(
|
||||
title = "Greataxe",
|
||||
hit = R.drawable.ic_d20_24,
|
||||
damage = R.drawable.ic_d12_24,
|
||||
),
|
||||
)
|
||||
)
|
||||
},
|
||||
counter = remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
CounterUio(
|
||||
title = "Rage",
|
||||
value = 1,
|
||||
max = 2,
|
||||
),
|
||||
)
|
||||
)
|
||||
},
|
||||
alterations = remember {
|
||||
mutableStateOf(listOf("Rage", "Attaque téméraire"))
|
||||
},
|
||||
weapons = rememberWeaponListStatePreview(),
|
||||
onBack = { },
|
||||
onInitiative = { },
|
||||
onStats = { },
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.facotry.displayable.ConvertActionIntoDisplayableFactory
|
||||
import com.pixelized.rplexicon.facotry.displayable.ConvertAttackIntoDisplayableFactory
|
||||
import com.pixelized.rplexicon.facotry.displayable.ConvertCharacterSheetIntoDisplayableFactory
|
||||
import com.pixelized.rplexicon.facotry.displayable.ConvertCounterIntoDisplayableFactory
|
||||
import com.pixelized.rplexicon.model.Action
|
||||
import com.pixelized.rplexicon.model.Attack
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.model.Roll
|
||||
|
|
@ -23,6 +23,7 @@ import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
|||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.ActionsUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.CounterUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.WeaponUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.context
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -38,7 +39,7 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
savedStateHandle: SavedStateHandle,
|
||||
private val characterSheetFactory: ConvertCharacterSheetIntoDisplayableFactory,
|
||||
private val counterFactory: ConvertCounterIntoDisplayableFactory,
|
||||
private val actionFactory: ConvertActionIntoDisplayableFactory,
|
||||
private val weaponFactory: ConvertAttackIntoDisplayableFactory,
|
||||
private val characterRepository: CharacterSheetRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val actionRepository: ActionRepository,
|
||||
|
|
@ -49,6 +50,7 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
val sheet: State<CharacterSheetUio?>
|
||||
val alterations: State<List<String>>
|
||||
val actions: State<List<ActionsUio>>
|
||||
val weapons: State<List<WeaponUio>>
|
||||
val counter: State<List<CounterUio>>
|
||||
|
||||
private val _isLoading = mutableStateOf(false)
|
||||
|
|
@ -72,8 +74,14 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
} ?: emptyList()
|
||||
)
|
||||
actions = mutableStateOf(
|
||||
actionRepository.find(name = argument.name)?.map {
|
||||
actionFactory.toUio(action = it)
|
||||
actionRepository.find(name = argument.name)?.mapNotNull {
|
||||
// actionFactory.toUio(attack = it)
|
||||
null
|
||||
} ?: emptyList()
|
||||
)
|
||||
weapons = mutableStateOf(
|
||||
actionRepository.find(name = argument.name)?.mapNotNull {
|
||||
weaponFactory.toUio(attack = it, characterSheet = model)
|
||||
} ?: emptyList()
|
||||
)
|
||||
|
||||
|
|
@ -86,8 +94,11 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
}
|
||||
launch {
|
||||
actionRepository.data.collect {
|
||||
actions.value = it[argument.name]?.map { action ->
|
||||
actionFactory.toUio(action = action)
|
||||
// actions.value = it[argument.name]?.mapNotNull { action ->
|
||||
// actionFactory.toUio(attack = action)
|
||||
// } ?: emptyList()
|
||||
weapons.value = it[argument.name]?.mapNotNull { action ->
|
||||
weaponFactory.toUio(attack = action, characterSheet = model)
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +150,7 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
fun onHitRoll(id: String): Roll {
|
||||
val action = actionRepository.find(argument.name)?.firstOrNull { it.title == id }
|
||||
return actionRoll(
|
||||
action = action,
|
||||
attack = action,
|
||||
throws = action?.hit,
|
||||
)
|
||||
}
|
||||
|
|
@ -147,7 +158,7 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
fun onDamageRoll(id: String): Roll {
|
||||
val action = actionRepository.find(argument.name)?.firstOrNull { it.title == id }
|
||||
return actionRoll(
|
||||
action = action,
|
||||
attack = action,
|
||||
throws = action?.damage,
|
||||
)
|
||||
}
|
||||
|
|
@ -519,44 +530,41 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun actionRoll(
|
||||
action: Action?,
|
||||
throws: Action.Throw?,
|
||||
attack: Attack?,
|
||||
throws: Attack.Throw?,
|
||||
): Roll {
|
||||
// build the title
|
||||
val title = context.getString(
|
||||
when (action?.type) {
|
||||
Action.Type.SPELL -> when (throws === action.hit) {
|
||||
true -> R.string.dice_roll_spell_hit_title
|
||||
else -> R.string.dice_roll_spell_damage_title
|
||||
}
|
||||
|
||||
else -> when (throws === action?.hit) {
|
||||
when (attack?.type) {
|
||||
else -> when (throws === attack?.hit) {
|
||||
true -> R.string.dice_roll_attack_hit_title
|
||||
else -> R.string.dice_roll_attack_damage_title
|
||||
}
|
||||
},
|
||||
action?.title,
|
||||
attack?.title,
|
||||
)
|
||||
// get the alteration for roll and a given player
|
||||
val alterations = when (action?.type) {
|
||||
Action.Type.PHYSICAL_MELEE_ATTACK -> {
|
||||
val alterations = when (attack?.type) {
|
||||
Attack.Type.PHYSICAL_MELEE_ATTACK -> {
|
||||
alterationRepository.getStatus(
|
||||
character = model.name,
|
||||
property = when (throws === action.hit) {
|
||||
property = when (throws === attack.hit) {
|
||||
true -> Property.PHYSICAL_MELEE_ATTACK
|
||||
else -> Property.PHYSICAL_MELEE_DAMAGE
|
||||
},
|
||||
)
|
||||
}
|
||||
Action.Type.PHYSICAL_RANGE_ATTACK -> {
|
||||
|
||||
Attack.Type.PHYSICAL_RANGE_ATTACK -> {
|
||||
alterationRepository.getStatus(
|
||||
character = model.name,
|
||||
property = when (throws === action.hit) {
|
||||
property = when (throws === attack.hit) {
|
||||
true -> Property.PHYSICAL_RANGE_ATTACK
|
||||
else -> Property.PHYSICAL_RANGE_DAMAGE
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
emptyList()
|
||||
}
|
||||
|
|
@ -568,10 +576,10 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
// build the roll
|
||||
return Roll(
|
||||
title = title,
|
||||
highlight = action?.title,
|
||||
highlight = attack?.title,
|
||||
dices = listOf(
|
||||
Roll.Dice(
|
||||
title = action?.title,
|
||||
title = attack?.title,
|
||||
advantage = advantage,
|
||||
disadvantage = disadvantage,
|
||||
fail = fail,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,167 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable
|
||||
|
||||
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.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
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.Stable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
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.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.model.Attack
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
@Stable
|
||||
data class WeaponUio(
|
||||
val id: Attack? = null,
|
||||
@DrawableRes val icon: Int,
|
||||
val name: String,
|
||||
val type: String,
|
||||
val range: String,
|
||||
val hit: Dice?,
|
||||
val damage: Dice?,
|
||||
) {
|
||||
@Stable
|
||||
class Dice(
|
||||
@DrawableRes val icon: Int,
|
||||
val label: String,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Weapon(
|
||||
modifier: Modifier = Modifier,
|
||||
weapon: WeaponUio,
|
||||
onHit: (String) -> Unit,
|
||||
onDamage: (String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = weapon.icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = weapon.name,
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontStyle = FontStyle.Italic,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = weapon.type,
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontStyle = FontStyle.Italic,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = weapon.range,
|
||||
)
|
||||
}
|
||||
weapon.hit?.let { dice ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.sizeIn(minWidth = 32.dp)
|
||||
.clickable { weapon.name.let(onHit) },
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = dice.icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
text = dice.label,
|
||||
)
|
||||
}
|
||||
}
|
||||
weapon.damage?.let { dice ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.sizeIn(minWidth = 42.dp)
|
||||
.clickable { weapon.name.let(onDamage) },
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = dice.icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
text = dice.label,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun WeaponPreview(
|
||||
@PreviewParameter(WeaponPreviewProvider::class) preview: WeaponUio,
|
||||
) {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
Weapon(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
weapon = preview,
|
||||
onHit = { },
|
||||
onDamage = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class WeaponPreviewProvider : PreviewParameterProvider<WeaponUio> {
|
||||
override val values: Sequence<WeaponUio> = sequenceOf(
|
||||
WeaponUio(
|
||||
icon = R.drawable.ic_crossed_swords_24,
|
||||
name = "Dagger",
|
||||
type = "Melee weapon",
|
||||
range = "5 ft reach",
|
||||
hit = WeaponUio.Dice(icon = R.drawable.ic_d20_24, label = "1d20"),
|
||||
damage = WeaponUio.Dice(icon = R.drawable.ic_d8_24, label = "1d8"),
|
||||
),
|
||||
WeaponUio(
|
||||
icon = R.drawable.ic_pocket_bow_24,
|
||||
name = "Long bow",
|
||||
type = "Ranged weapon",
|
||||
range = "30 ft reach",
|
||||
hit = WeaponUio.Dice(icon = R.drawable.ic_d20_24, label = "1d20+5"),
|
||||
damage = WeaponUio.Dice(icon = R.drawable.ic_d8_24, label = "1d8+3"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,66 +1,38 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.pages
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.CutCornerShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.Action
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.ActionsUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.Counter
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.CounterUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.Weapon
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.WeaponUio
|
||||
|
||||
@Composable
|
||||
fun ActionsPages(
|
||||
modifier: Modifier = Modifier,
|
||||
actions: State<List<ActionsUio>>,
|
||||
counter: State<List<CounterUio>>,
|
||||
alterations: State<List<String>>,
|
||||
lazyListState: LazyListState = rememberLazyListState(),
|
||||
weapons: State<List<WeaponUio>>,
|
||||
onHit: (id: String) -> Unit,
|
||||
onDamage: (id: String) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
state = lazyListState,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
counter.value.forEach {
|
||||
Counter(
|
||||
counter = it,
|
||||
)
|
||||
}
|
||||
actions.value.forEach {
|
||||
Action(
|
||||
action = it,
|
||||
onHit = onHit,
|
||||
onDamage = onDamage,
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.ddBorder(
|
||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||
outline = remember { CutCornerShape(size = 16.dp) },
|
||||
)
|
||||
.padding(all = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
alterations.value.forEach {
|
||||
Text(
|
||||
text = it
|
||||
)
|
||||
}
|
||||
items(items = weapons.value) {
|
||||
Weapon(
|
||||
weapon = it,
|
||||
onHit = onHit,
|
||||
onDamage = onDamage,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.pixelized.rplexicon.ui.screens.character.pages
|
|||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
|
@ -9,8 +10,10 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CutCornerShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -40,6 +43,7 @@ import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
|||
@Composable
|
||||
fun ProficiencyPage(
|
||||
modifier: Modifier = Modifier,
|
||||
state: ScrollState = rememberScrollState(),
|
||||
inner: Shape = remember { RoundedCornerShape(size = 8.dp) },
|
||||
outline: Shape = remember { CutCornerShape(size = 16.dp) },
|
||||
sheet: CharacterSheetUio,
|
||||
|
|
@ -47,7 +51,7 @@ fun ProficiencyPage(
|
|||
onStats: (StatUio) -> Unit,
|
||||
onProficiencies: (ProficiencyUio) -> Unit,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
Box(modifier = modifier.verticalScroll(state = state)) {
|
||||
ProficiencyLayout(
|
||||
inner = inner,
|
||||
outline = outline,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.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.WeaponUio
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun rememberWeaponListStatePreview(): State<List<WeaponUio>> = remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
WeaponUio(
|
||||
icon = R.drawable.ic_crossed_swords_24,
|
||||
name = "Dagger",
|
||||
type = "Melee weapon",
|
||||
range = "5 ft reach",
|
||||
hit = WeaponUio.Dice(icon = R.drawable.ic_d20_24, label = "1d20"),
|
||||
damage = WeaponUio.Dice(icon = R.drawable.ic_d8_24, label = "1d8"),
|
||||
),
|
||||
WeaponUio(
|
||||
icon = R.drawable.ic_pocket_bow_24,
|
||||
name = "Long bow",
|
||||
type = "Ranged weapon",
|
||||
range = "30 ft reach",
|
||||
hit = WeaponUio.Dice(icon = R.drawable.ic_d20_24, label = "1d20+5"),
|
||||
damage = WeaponUio.Dice(
|
||||
icon = R.drawable.ic_d8_24,
|
||||
label = "1d8+3"
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
4
app/src/main/res/drawable/ic_crossed_swords_24.xml
Normal file
4
app/src/main/res/drawable/ic_crossed_swords_24.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="24dp" android:viewportHeight="512"
|
||||
android:viewportWidth="512" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M19.75,14.44c59.54,112.29 142.51,202.35 232.28,292.72l3.63,3.75 0.06,-0.06c21.83,21.93 44.04,43.92 66.4,66.25 -18.86,14.81 -38.97,28.2 -59.94,40.31l28.53,28.53 68.72,-68.72c42.34,27.64 76.29,63.65 104.09,105.81l28.06,-28.06c-42.47,-27.49 -79.74,-60.21 -106.03,-103.88l68.94,-68.94 -28.53,-28.53c-11.11,21.85 -24.41,42.01 -39.47,60.59 -43.85,-43.8 -86.46,-85.84 -130.13,-125.47 -0.22,-0.2 -0.43,-0.42 -0.66,-0.63C183.62,122.75 108.51,63.91 19.75,14.44zM491.63,14.44c-83.04,46.28 -154.12,100.78 -221.97,161.16l22.81,21.56 56.81,-56.81 13.22,13.19 -56.44,56.44 24.59,23.19c61.8,-66.92 117.6,-136.92 160.97,-218.72zM162.1,140.34l200.56,200.53c-4.36,4.44 -8.84,8.79 -13.4,13.03L148.88,153.53l13.22,-13.19zM85.4,253.62l-28.5,28.53 68.91,68.91c-26.29,43.67 -63.53,76.41 -106,103.91l28.06,28.06c27.81,-42.16 61.76,-78.17 104.09,-105.81l68.72,68.72 28.53,-28.53c-20.96,-12.11 -41.08,-25.5 -59.94,-40.31 17.86,-17.83 35.61,-35.43 53.16,-52.97l-24.84,-25.66 -55.47,55.47c-4.57,-4.24 -9.01,-8.62 -13.37,-13.06l55.84,-55.84 -24.53,-25.37c-18.28,17.86 -36.6,36.06 -55.16,54.59 -15.07,-18.59 -28.38,-38.76 -39.5,-60.63z"/>
|
||||
</vector>
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#e53935"
|
||||
android:pathData="M35.25,31.001C36.283,31.724 37,33 37,34c0,1.25 -0.25,2.125 -1.125,3c0,0 0.125,0.125 0.75,0.125c3.5,0 4.375,-1.944 4.375,-2.625c0,-2 -2,-2.5 -2,-2.5c0.625,-0.015 1.218,0.034 1.806,0.185c1.683,0.431 2.943,1.374 3.729,2.924c0.306,0.604 0.456,1.206 0.464,1.794c0.016,1.159 -0.5,2.346 -1.625,3.346C41.525,41.894 38.125,42 38,42c0.329,0.363 1.25,1.125 2.625,1.125C41.25,43.125 42,43 42,43c-0.036,0.047 -0.75,0.875 -2.64,1.576C38.584,44.835 37.798,44.988 37,45c-0.47,0.007 -0.943,-0.035 -1.42,-0.132c-1.906,-0.386 -3.215,-1.502 -4.036,-3.206C31.27,41.094 31,39.875 31,39.625c-0.618,0.604 -0.977,1.337 -1,2.125c0.125,1.625 1.013,2.232 1,2.25c-0.144,-0.059 -3,-0.625 -3,-4.625c-0.013,-0.642 0.003,-1.161 0,-1.75c-0.005,-1.031 -0.475,-1.89 -1.282,-2.555c-1.359,-1.12 -2.723,-2.236 -4.093,-3.343c-0.935,-0.756 -1.518,-1.686 -1.531,-2.901c-0.008,-0.758 -0.367,-1.313 -0.959,-1.76c-0.372,-0.281 -0.749,-0.561 -1.086,-0.88c-0.595,-0.564 -0.706,-1.262 -0.503,-2.047c0.035,0.029 0.064,0.041 0.068,0.059c0.233,0.944 0.953,1.287 1.831,1.429c0.471,0.076 0.951,0.109 1.416,0.208c0.488,0.105 0.765,0.449 0.877,0.92c0.069,0.291 0.124,0.586 0.192,0.877c0.131,0.561 0.416,0.795 0.997,0.832c0.382,0.024 0.765,0.043 1.146,0.081c0.597,0.06 1.115,0.299 1.578,0.676c1.614,1.314 3.236,2.619 4.851,3.931C31.917,33.488 32.625,34 33.375,34c0.875,0 2,-0.625 2,-1.875C35.375,31.375 35.25,31.001 35.25,31.001z" />
|
||||
<path
|
||||
android:fillColor="#e53935"
|
||||
android:pathData="M25.891,36.073c-1.139,-0.939 -2.284,-1.872 -3.431,-2.802 -0.641,1.039 -3.108,4.728 -6.589,4.728 -1.726,0 -3.306,-1.013 -4.121,-2.592 -0.49,-0.95 -0.75,-2.052 -0.75,-3.031 0,-4.25 2.675,-6.575 2.739,-6.658 -0.726,-0.179 -1.273,-0.103 -1.864,0.29 -0.598,0.398 -1.679,1.077 -1.758,1.119C10,27.125 10,27.125 10,27l0.375,-2.5C9.799,24.694 8.5,25.375 7,26.875c-0.75,0.75 -1.357,1.416 -1.357,1.416C5.25,26.875 5.875,24.375 5.997,23.5 6.069,22.99 5.872,23 5.872,23c-0.25,0 -0.997,0.765 -1.372,1.156 -1.159,1.206 -1.895,2.584 -2.31,4.208C2.112,28.672 2.063,29.063 2,29.375 2.024,29.383 2.625,28.5 3.125,28.5c0.25,0 0.265,0.383 0.257,0.518 -0.013,0.209 -0.084,0.418 -0.15,0.621C2.768,31.074 2.503,32.525 2.492,34c-0.005,0.676 0.044,1.356 0.151,2.042 0.183,1.167 0.467,2.021 0.981,3.083 0.726,1.5 2.033,2.812 2.125,2.875 -0.063,-0.214 -0.188,-0.505 -0.209,-0.67 -0.042,-0.319 -0.107,-0.647 -0.072,-0.962 0.044,-0.396 0.39,-0.486 0.678,-0.206 0.129,0.126 1.545,1.465 2.38,2.011 1.893,1.236 3.89,1.82 5.974,1.827 1.083,0.004 2.189,-0.148 3.317,-0.444 1.632,-0.429 3.072,-1.223 4.356,-2.295 1.645,-1.372 2.912,-3.132 3.921,-4.989C26.028,36.205 25.969,36.137 25.891,36.073zM31.32,22.083c-1.992,1.314 -3.654,3.497 -5.105,5.364 -0.01,0.013 -0.016,0.027 -0.023,0.04 0.451,0.164 0.881,0.4 1.28,0.725 0.533,0.434 1.067,0.865 1.601,1.298 0.043,-0.087 0.083,-0.166 0.118,-0.239 0.989,-2.037 2.183,-4.476 3.696,-6.181 1.478,-1.666 4.073,-2.181 5.999,-1.251 0.24,0.116 0.434,0.167 0.624,0.16 0.194,-0.007 0.384,-0.073 0.615,-0.193 1.506,-0.778 3.133,-1.17 4.829,-1.159C45.288,20.65 46,20.75 46,20.75c-0.625,-0.625 -1.444,-1.26 -2.156,-1.661C42.519,18.344 41.157,18 39.75,18c-2,0 -3,0.624 -3.535,0.624 -0.215,0 -0.32,-0.058 -0.394,-0.156 -0.065,-0.085 -0.04,-0.276 0.01,-0.395C36.125,17.5 36.934,17.045 37,17c-0.625,0 -2.003,0.741 -2.796,1.355 -0.533,0.412 -1.062,0.829 -1.599,1.236 -0.108,0.082 -0.238,0.147 -0.368,0.185 -0.353,0.103 -0.533,-0.071 -0.429,-0.414 0.047,-0.154 0.119,-0.304 0.199,-0.444 0.129,-0.227 0.275,-0.445 0.425,-0.683 -3.807,2.391 -4.459,5.671 -4.432,5.641 1.118,-1.216 2.382,-2.165 3.875,-2.875 1.495,-0.711 3.125,-1.125 5,-1.125 0,0 0.125,0.101 0.125,0.125 0,0 -0.75,0 -1.545,0.237C33.954,20.583 32.592,21.243 31.32,22.083z" />
|
||||
<path
|
||||
android:fillColor="#e53935"
|
||||
android:pathData="M16.75,11.25c0,0.5 0.132,0.997 0.275,1.413c0.372,1.086 1.086,1.964 1.899,2.76c0.802,0.785 1.649,1.525 2.467,2.294c0.825,0.775 1.542,1.63 1.968,2.686c0.241,0.597 0.36,1.216 0.266,1.858c-0.026,0.179 0.04,0.265 0.199,0.333c0.406,0.173 0.664,0.46 0.686,0.915c0.01,0.215 0.144,0.181 0.273,0.114c0.716,-0.372 1.045,-0.935 1.091,-0.997c0.082,0.171 0.127,0.383 0.125,0.625c-0.012,1.346 -1.205,3.555 -2.328,3.995c0.015,-0.098 0.026,-0.177 0.04,-0.256c0.158,-0.888 -0.284,-1.616 -1.153,-1.906c-0.587,-0.196 -1.072,-0.2 -1.685,-0.209c-0.094,-0.001 -0.357,0 -0.5,0c0.047,-0.108 0.393,-0.823 0.47,-1.101c0.11,-0.395 -0.034,-0.677 -0.439,-0.766c-0.439,-0.097 -0.896,-0.158 -1.345,-0.156c-1.032,0.005 -2.055,0.129 -3.059,0.372c-0.14,0.034 -0.366,0.106 -0.503,0.151c0.875,0 2,0.375 2,0.375s-0.5,1 -0.5,1.625c0,0.5 0.25,0.875 0.5,0.875S17.886,26.082 18,26c-0.023,0.136 -0.161,0.855 -0.18,1.193C17.791,27.724 18,28 18.625,28c0.125,0 0.25,0 0.375,0c-0.25,0.875 -2.132,2.027 -3.25,2c-0.074,-0.002 -0.143,-0.009 -0.208,-0.022C16,29.75 16.69,28.875 16.69,28.501l-1.492,0.19c0,0 0.509,-0.635 0.672,-0.954c0.423,-0.825 0.47,-1.668 -0.09,-2.456c-0.473,-0.666 -1.239,-0.951 -2.03,-1.03c-1.25,0 -1.9,0.35 -2,0.375c0.569,-1.24 1.381,-2.005 2.625,-2.625c-1,-0.5 -2,-0.625 -2,-0.625c1,-0.625 2.5,-1.125 3.625,-1.375c-0.125,0 -0.437,0.004 -0.5,0c-3.75,0 -5.219,1.938 -5.25,2c0.605,0.104 1,0.125 1.75,0.375c0,0 -2,0.375 -5,2.625c0.02,-0.113 0.375,-0.875 0.375,-1.625c0,-2.625 -3.324,-2.099 -3.375,-2.125c0.081,-0.073 0.75,-0.625 2.863,-1.645c0.396,-0.214 1.512,-0.73 1.512,-1.355c0,-0.875 -1.735,-2.15 -1.875,-2.25c1.375,0 2.147,0.129 3.25,0.375c-0.588,-1.004 -0.752,-2.05 -0.486,-3.088c0.426,0.8 1.038,1.428 1.784,1.92c0.686,0.453 1.409,0.852 2.111,1.282c0.532,0.326 1.084,0.628 1.576,1.005c0.378,0.29 0.677,0.681 1.008,1.028c0.055,0.058 0.099,0.126 0.149,0.189c0.029,-0.014 0.057,-0.028 0.086,-0.042c-0.079,-0.197 -0.142,-0.402 -0.239,-0.591c-0.393,-0.765 -0.974,-1.378 -1.693,-1.852c-0.295,-0.195 -0.456,-0.426 -0.513,-0.753c-0.171,-0.969 -0.175,-1.919 0.011,-2.85C13.645,12.121 14.25,11 14.25,11v0.125c0.034,1.325 0.538,2.386 1.375,3.375c0.878,1.037 2.027,1.805 3.017,2.73c1.733,1.645 2.471,2.568 2.608,2.77c0,0 -0.051,-0.214 -0.082,-0.283c-0.476,-1.091 -1.247,-1.97 -2.11,-2.778c-0.75,-0.702 -1.512,-1.393 -2.275,-2.082c-0.276,-0.25 -0.439,-0.547 -0.483,-0.91C16.125,12.5 16.737,11.259 16.75,11.25zM19,20c0,0 0.08,0.497 0.199,0.743C19.75,21.875 21,22 21,22s0,-0.875 -1.25,-1.75C19.381,19.992 19,20 19,20z" />
|
||||
<path
|
||||
android:fillColor="#e53935"
|
||||
android:pathData="M8,12.625C8.25,11.375 9,10 9,10s0.463,1.573 1.25,2.625c0.389,0.52 0.909,1.098 1.514,1.497c0.114,0.075 0.229,0.149 0.346,0.222c-0.022,-0.674 0.031,-1.334 0.159,-1.974c0.109,-0.545 0.492,-1.328 0.73,-1.784V10.5C13,8.567 14.343,7 16,7s3,1.567 3,3.5c0,1.377 -0.111,2.059 -0.271,2.5c-0.014,0.037 -0.028,0.071 -0.042,0.106c0.131,0.212 0.287,0.426 0.465,0.645c0.011,0.013 0.02,0.026 0.031,0.039c0.187,0.226 0.4,0.459 0.65,0.704c0.471,0.461 0.976,0.922 1.463,1.367c0.33,0.301 0.66,0.602 0.985,0.908c0.079,0.074 0.142,0.147 0.217,0.221C24.042,15.314 25,13.142 25,11c0,-5 -4.029,-8 -9,-8s-9,3.125 -9,8c0,1.216 0.318,2.439 0.865,3.58C7.829,14.041 7.892,13.167 8,12.625z" />
|
||||
</vector>
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_pocket_bow_24.xml
Normal file
9
app/src/main/res/drawable/ic_pocket_bow_24.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m78,12 l9,70 -69,-11 41,56 -11,323c-11,13 -20,29 -25,48 74,-56 152,-72 223,-101l-36,-36c-53,25 -106,42 -142,71l9,-280 8,10 3,5h71l200,227c15,-14 29,-28 42,-45L172,156L172,84l-12,-9 273,-11c-30,37 -47,89 -71,143l36,36c30,-70 45,-148 101,-221 -19,5 -34,13 -47,23L137,57 78,12zM102,54 L153,93v55L99,148L60,97l49,8 -7,-51zM351,222c-9,13 -17,26 -27,38l31,26 34,-26 -38,-38zM451,312c-36,57 -76,100 -135,136 59,20 118,37 179,44 -9,-61 -24,-121 -44,-180zM266,317c-13,11 -27,22 -42,31l38,38c8,-15 18,-28 29,-41l-25,-28z" />
|
||||
</vector>
|
||||
4
app/src/main/res/drawable/ic_scroll_unfurled_24.xml
Normal file
4
app/src/main/res/drawable/ic_scroll_unfurled_24.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="24dp" android:viewportHeight="512"
|
||||
android:viewportWidth="512" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M103.43,17.84c-1.12,0 -2.23,0.03 -3.35,0.08 -2.55,0.11 -5.08,0.33 -7.6,0.68 -20.17,2.75 -39.16,13.67 -52.32,33.67 -24.61,37.4 2.19,98.03 56.63,98.03 0.54,0 1.06,-0.01 1.58,-0.02v0.7h60.56c-10.76,31.99 -30.3,66.6 -52.45,101.43 -2.16,3.4 -4.25,6.88 -6.29,10.41l34.88,35.73 -56.26,9.42c-32.73,85.97 -27.42,182.07 48.28,182.07v-0l9.31,0.07c23.83,-0.57 46.73,-4.3 61.33,-12.89 4.17,-2.46 7.63,-5.24 10.47,-8.42h-32.45c-20.33,5.95 -40.8,-6.94 -47.4,-25.92 -8.96,-25.77 7.52,-52.36 31.87,-60.45 5.8,-1.93 11.72,-2.83 17.57,-2.83v-0.41h178.33c-0.57,-44.4 16.35,-90.13 49.18,-126 23.95,-26.18 42.03,-60.62 51.3,-94.85l-41.22,-24.93 38.27,-6.91 -43.37,-25.81h-0l0,-0 0,0 52.13,-8.85c-5.23,-39.13 -28.84,-68.11 -77.37,-68.11C341.14,32.26 222.11,35.29 149.34,28.5c-14.89,-6.76 -30.55,-10.72 -45.91,-10.65zM103.9,36.55c13.14,0.04 27.41,3.8 41.25,10.63l0.03,-0.07c4.67,4.74 8.54,9.74 11.68,14.98L82.92,62.09l10.57,14.78c10.61,14.83 19.8,31.99 21.09,42.02 0.64,5.02 -0.11,7.17 -1.81,8.84 -1.71,1.67 -6.23,3.88 -15.99,3.88 -40.59,0 -56.88,-44.95 -41.01,-69.06C66.24,46.64 79.58,39.22 95,37.12c2.89,-0.4 5.86,-0.58 8.89,-0.57zM118.5,80.78h46.28c4.28,15.73 3.66,33.07 -0.54,51.51L131.52,132.29c1.9,-5.03 2.27,-10.57 1.6,-15.77 -1.53,-11.91 -7.41,-24.07 -14.62,-35.74zM220.05,397.88c6.44,6.84 11.19,15.31 13.37,24.91 3.8,16.74 3.09,31.21 -1.77,43.2 -4.53,11.18 -12.58,19.79 -22.29,26h237.19c14.45,0 24.89,-5.68 32.2,-14.32 7.31,-8.64 11.2,-20.51 10.7,-32.35 -0.19,-4.47 -0.98,-8.91 -2.41,-13.18l-69.91,-8.2 42.02,-20.53c-8.32,-3.44 -18.64,-5.54 -31.38,-5.54L220.05,397.87zM177.39,398.38c-1.15,-0 -2.31,0.05 -3.46,0.15 -2.63,0.24 -5.26,0.77 -7.82,1.63 -15.11,5.02 -25.34,21.54 -20.11,36.58 3.67,10.57 15.35,17.71 25.65,13.94l1.55,-0.57h43.35c0.95,-6.36 0.75,-13.88 -1.36,-23.19 -3.71,-16.36 -20.54,-28.48 -37.81,-28.54z"/>
|
||||
</vector>
|
||||
4
app/src/main/res/drawable/ic_treasure_map_24.xml
Normal file
4
app/src/main/res/drawable/ic_treasure_map_24.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="24dp" android:viewportHeight="512"
|
||||
android:viewportWidth="512" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M227.4,34.7c-10.1,0 -20.2,0.2 -30.2,0.5l6.1,65.6 -61.1,-62.5c-31.3,2.5 -62.5,6.6 -93.8,12.5l34.2,28.4 -48,-0.6c35.1,100.2 6.9,182.6 -0.3,292.1L130,476.5c10,-1.3 19.9,-2.4 29.6,-3.3l21.5,-42.2 18.6,28.8 41.5,-33.5 0.8,43c82.9,-0.2 157.7,9.1 235.7,7.9 -28.2,-73 -31.2,-143.6 -31.9,-209.2l-33.3,-19.1 32.7,-33.9c-0.4,-21.3 -1.3,-42 -3.6,-61.9l-57.4,0.7 50.2,-41.7c-3.8,-15.5 -9,-30.4 -16.1,-44.7l-29.5,-23.9C335,38 281.2,34.6 227.4,34.7zM286.1,71.7c10.6,24.75 21.1,49.5 31.7,74.3 7.5,-10.5 14.9,-21 22.4,-31.5 16,27.2 32,54.3 48,81.5l-16.2,9.5 -33.3,-56.7 -42.5,59.4 -15.2,-10.9 24,-33.5 -21.9,-51.5 -24.6,40.1 12,22.6 -16.5,8.8 -18.3,-34.5 -24.8,58.2 -17.2,-7.4 32.5,-76.2 7.7,-18c4.8,9.2 9.6,18.3 14.5,27.4 12.5,-20.6 25.1,-41.11 37.7,-61.6zM91.2,128c6.72,1.6 13.4,3.4 19.2,5.3 -2.1,5.9 -4.1,11.8 -6.2,17.6 -5.79,-1.6 -11.72,-3.4 -16.9,-4.7 1.39,-6 2.62,-12.1 3.9,-18.2zM129.1,141.4c6.3,3.8 12,7.2 17,12.8L132.6,167c-4,-3.7 -8.6,-7 -12.8,-9.4zM157.8,173.7c2.1,7.4 2.1,15.7 1.6,22.5l-18.5,-2.4c0.1,-5.1 0.3,-10 -1,-14.5zM136.6,209.4l17.2,7.1c-3.3,6.6 -5.1,12.7 -8.6,17.8l-16.3,-9c2.6,-5.4 5.6,-10.8 7.7,-15.9zM120.1,243.5l17.7,6.1c-1.5,5.4 -3,11.2 -3.6,16.2l-18.6,-2c1.3,-7.5 2.1,-14 4.5,-20.3zM327.9,260.9c8.5,1 14.6,3 21.7,7.1l-9.8,16c-4.1,-2.8 -9.4,-3.8 -13.5,-4.5zM306.7,262.4c1.1,6.1 2.5,12.2 3.9,18.3 -5.9,1.3 -11.7,3.3 -16.5,5.1l-6.8,-17.4c6.7,-2.4 13.5,-4.7 19.4,-6zM268.8,278.3l11,15.1c-5.6,4 -11.8,7.8 -16.8,10.6l-8.9,-16.4c5.1,-2.9 10.6,-6.3 14.7,-9.3zM135.3,281c1.5,4.7 4.2,9.2 6.9,12.1l-13.8,12.6c-5.5,-5.7 -9.5,-13.5 -11.2,-20.1zM365.6,284.3c3.5,6.4 6.8,12.7 8.7,19.1l-17.8,5.6c-2,-5.4 -4.3,-10.8 -6.8,-14.8zM238.2,295.2l6.9,17.3c-6.4,2.7 -12.9,4.8 -18.6,6.5l-5,-18c5.9,-1.6 11.3,-3.8 16.7,-5.8zM154.4,301.4c5.3,1.7 10.8,3.4 15.7,4.2 -1.2,6.1 -2,12.3 -2.8,18.5 -7,-1 -14.5,-3.3 -20.5,-5.7zM204.4,304.9l2.8,18.5c-7.2,1.3 -13.4,1.6 -19.8,1.9l-0.4,-18.7c5.9,-0.2 11.6,-0.8 17.4,-1.7zM378.9,322.9c1,6.4 1.6,12.9 2.2,19.3l-18.7,1.5c-0.4,-6 -0.9,-11.9 -2,-17.8zM311.3,353.7c18.9,3.5 44.9,16.2 68.9,33.9 7.4,-9.9 14.4,-20.4 21.3,-31.1l30.1,12.9c-4.7,12.3 -15,25.6 -28.6,37.2 17,16.2 30.9,34.5 37,53 -13.8,-18.1 -31.1,-31.8 -50.3,-42.8 -23.4,15.8 -52.7,25.9 -79.6,20.4 22.9,-4.4 40.6,-16.6 55.8,-32.6 -16.5,-7.5 -33.8,-13.9 -51.3,-20.1z"/>
|
||||
</vector>
|
||||
File diff suppressed because one or more lines are too long
4
app/src/main/res/drawable/ic_visored_helm_24.xml
Normal file
4
app/src/main/res/drawable/ic_visored_helm_24.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="24dp" android:viewportHeight="512"
|
||||
android:viewportWidth="512" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M258.09,18.5c-74.34,0 -138.07,62.5 -156.19,148.44 52.76,-7.7 102.23,-22.04 153.94,-45.09l4.13,-1.81 3.97,2.06c49.42,25.67 97.65,41.03 150.66,46.41 -17.66,-86.74 -81.71,-150 -156.5,-150zM259.37,140.66c-57.41,25.15 -112.88,39.99 -172.53,47 6.72,32.85 6.91,65.93 -0.5,98.94 89.29,41.6 231.65,43.15 340.59,-0.13 -10.76,-32.52 -11.73,-65.66 -1.19,-98.41 -59.03,-4.24 -112.63,-20.06 -166.38,-47.41zM245.87,173.78h18.72v127.75h-18.72L245.87,173.78zM187.09,184.97h18.69v101.65h-18.69L187.09,184.97zM302.81,184.97h18.69v101.65h-18.69L302.81,184.97zM131.09,199.88h18.69v79.28h-18.69v-79.28zM358.81,199.88h18.69v79.28h-18.69v-79.28zM397.56,316.63c-14.3,4.28 -28.96,7.87 -43.78,10.84l-19.22,64.06c26.11,-17.34 48,-43.31 63,-74.9zM120.03,319.5c13.95,28.26 33.45,51.85 56.56,68.53l-17.69,-58.9c-13.4,-2.61 -26.39,-5.83 -38.88,-9.63zM333.19,331.16c-51.63,8.18 -104.75,8.59 -153.72,1.44l20.84,69.5c18,8.52 37.49,13.19 57.78,13.19 18.59,0 36.51,-3.92 53.22,-11.12l21.88,-73zM137.69,378.31c-19.44,21.56 -36.42,44.37 -48.59,72.16 70.23,-8.74 133.74,14.68 168.03,50.75 39.68,-35.61 103.71,-55.69 170.88,-44.25 -15.08,-29.37 -33.32,-51.98 -53.94,-74 -31.19,31.75 -71.53,51 -115.97,51 -46.57,0 -88.65,-21.14 -120.41,-55.66z"/>
|
||||
</vector>
|
||||
Loading…
Add table
Add a link
Reference in a new issue