Refactor repositories by adding parsers.
Add character sheet poc.
This commit is contained in:
parent
bb760392f0
commit
87a1471efe
17 changed files with 761 additions and 286 deletions
|
|
@ -2,6 +2,7 @@ package com.pixelized.rplexicon
|
|||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
|
|
@ -19,6 +20,7 @@ import androidx.compose.runtime.staticCompositionLocalOf
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
import com.pixelized.rplexicon.facotry.RollParser
|
||||
import com.pixelized.rplexicon.ui.navigation.ScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.pixelized.rplexicon.facotry
|
||||
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import javax.inject.Inject
|
||||
|
||||
class GenderParser @Inject constructor() {
|
||||
|
||||
fun parse(gender: String?): Lexicon.Gender {
|
||||
return when (gender?.takeIf { it.isNotBlank() }) {
|
||||
Gender.MALE -> Lexicon.Gender.MALE
|
||||
Gender.FEMALE -> Lexicon.Gender.FEMALE
|
||||
else -> Lexicon.Gender.UNDETERMINED
|
||||
}
|
||||
}
|
||||
|
||||
private object Gender {
|
||||
const val MALE = "Male"
|
||||
const val FEMALE = "Femelle"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.pixelized.rplexicon.facotry
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
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 LexiconParser @Inject constructor(
|
||||
private val portraitParser: PortraitParser,
|
||||
private val genderParser: GenderParser,
|
||||
private val raceParser: RaceParser,
|
||||
) {
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
fun parse(data: ValueRange): List<Lexicon> {
|
||||
val sheet = data.values.sheet()
|
||||
lateinit var sheetStructure: Map<String, Int>
|
||||
var id = 0
|
||||
|
||||
return sheet?.mapIndexedNotNull { index, row ->
|
||||
when {
|
||||
index == 0 -> {
|
||||
sheetStructure = row.checkSheetStructure(model = COLUMNS)
|
||||
null
|
||||
}
|
||||
|
||||
row is List<*> -> {
|
||||
val name = row.getOrNull(sheetStructure.name) as? String
|
||||
val diminutive = row.getOrNull(sheetStructure.diminutive) as? String?
|
||||
val gender = row.getOrNull(sheetStructure.gender) as? String?
|
||||
val race = row.getOrNull(sheetStructure.race) as? String?
|
||||
val portrait = row.getOrNull(sheetStructure.portrait) as? String?
|
||||
val description = row.getOrNull(sheetStructure.description) as? String?
|
||||
val history = row.getOrNull(sheetStructure.history) as? String?
|
||||
val tags = row.getOrNull(sheetStructure.tags) as? String?
|
||||
|
||||
if (name != null) {
|
||||
Lexicon(
|
||||
id = id++,
|
||||
sheetIndex = index,
|
||||
name = name,
|
||||
diminutive = diminutive?.takeIf { it.isNotBlank() },
|
||||
gender = genderParser.parse(gender),
|
||||
race = raceParser.parser(race),
|
||||
portrait = portraitParser.parse(portrait),
|
||||
description = description?.takeIf { it.isNotBlank() },
|
||||
history = history?.takeIf { it.isNotBlank() },
|
||||
tags = tags?.takeIf { it.isNotBlank() },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private val Map<String, Int>.name: Int get() = getValue(COLUMNS[0])
|
||||
private val Map<String, Int>.diminutive: Int get() = getValue(COLUMNS[1])
|
||||
private val Map<String, Int>.gender: Int get() = getValue(COLUMNS[2])
|
||||
private val Map<String, Int>.race: Int get() = getValue(COLUMNS[3])
|
||||
private val Map<String, Int>.portrait: Int get() = getValue(COLUMNS[4])
|
||||
private val Map<String, Int>.description: Int get() = getValue(COLUMNS[5])
|
||||
private val Map<String, Int>.history: Int get() = getValue(COLUMNS[6])
|
||||
private val Map<String, Int>.tags: Int get() = getValue(COLUMNS[7])
|
||||
|
||||
companion object {
|
||||
private val COLUMNS = listOf(
|
||||
"Nom",
|
||||
"Diminutif",
|
||||
"Sexe",
|
||||
"Race",
|
||||
"Portrait",
|
||||
"Description",
|
||||
"Histoire",
|
||||
"Mots clés",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.pixelized.rplexicon.facotry
|
||||
|
||||
import android.net.Uri
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.model.Location
|
||||
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 LocationParser @Inject constructor() {
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
fun parse(data: ValueRange): List<Location> {
|
||||
var id = 0
|
||||
var sheetStructure: Map<String, Int>? = null
|
||||
|
||||
return data.values.sheet()?.mapIndexedNotNull { index, item ->
|
||||
when {
|
||||
index == 0 -> {
|
||||
sheetStructure = item.checkSheetStructure(COLUMNS)
|
||||
null
|
||||
}
|
||||
|
||||
item is List<*> -> {
|
||||
val name = item.getOrNull(sheetStructure.name) as? String
|
||||
val uri = item.getOrNull(sheetStructure.uri)?.toString()?.let { Uri.parse(it) }
|
||||
|
||||
if (name != null && uri != null) {
|
||||
Location(
|
||||
id = id++,
|
||||
sheetIndex = index,
|
||||
name = name,
|
||||
uri = uri,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private val Map<String, Int>?.name: Int get() = this?.getValue(COLUMNS[0]) ?: 0
|
||||
private val Map<String, Int>?.uri: Int get() = this?.getValue(COLUMNS[1]) ?: 1
|
||||
|
||||
companion object {
|
||||
private val COLUMNS = listOf(
|
||||
"nom", "carte"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.pixelized.rplexicon.facotry
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.model.Location
|
||||
import com.pixelized.rplexicon.utilitary.extentions.checkSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||
import javax.inject.Inject
|
||||
|
||||
class MarqueeParser @Inject constructor() {
|
||||
|
||||
fun parse(data: ValueRange): List<Location.Marquee> {
|
||||
val sheet = data.values.sheet()
|
||||
lateinit var structure: Map<String, Int>
|
||||
|
||||
return sheet?.mapIndexedNotNull { index, item ->
|
||||
when {
|
||||
index == 0 -> {
|
||||
structure = item.checkSheetStructure(model = COLUMNS)
|
||||
null
|
||||
}
|
||||
|
||||
item is List<*> -> {
|
||||
val map = item.getOrNull(structure.map) as? String
|
||||
val name = item.getOrNull(structure.name) as? String
|
||||
val x = (item.getOrNull(structure.x) as? String)?.toFloatOrNull()
|
||||
val y = (item.getOrNull(structure.y) as? String)?.toFloatOrNull()
|
||||
val description = item.getOrNull(structure.description) as? String?
|
||||
|
||||
if (map != null && name != null && x != null && y != null) {
|
||||
Location.Marquee(
|
||||
map = map,
|
||||
name = name,
|
||||
x = x,
|
||||
y = y,
|
||||
description = description,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private val Map<String, Int>.map: Int get() = getValue(COLUMNS[0])
|
||||
private val Map<String, Int>.name: Int get() = getValue(COLUMNS[1])
|
||||
private val Map<String, Int>.x: Int get() = getValue(COLUMNS[2])
|
||||
private val Map<String, Int>.y: Int get() = getValue(COLUMNS[3])
|
||||
private val Map<String, Int>.description: Int get() = getValue(COLUMNS[4])
|
||||
|
||||
companion object {
|
||||
private val COLUMNS = listOf(
|
||||
"carte", "nom", "x", "y", "description"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.pixelized.rplexicon.facotry
|
||||
|
||||
import android.net.Uri
|
||||
import com.pixelized.rplexicon.utilitary.extentions.toUriOrNull
|
||||
import javax.inject.Inject
|
||||
|
||||
class PortraitParser @Inject constructor() {
|
||||
|
||||
fun parse(value: String?): List<Uri> {
|
||||
return value?.split(SEPARATOR)?.mapNotNull { it.toUriOrNull() } ?: emptyList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SEPARATOR = "\n"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.pixelized.rplexicon.facotry
|
||||
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.model.QuestEntry
|
||||
import com.pixelized.rplexicon.utilitary.extentions.checkSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||
import com.pixelized.rplexicon.utilitary.extentions.toUriOrNull
|
||||
import javax.inject.Inject
|
||||
|
||||
class QuestParser @Inject constructor() {
|
||||
|
||||
fun parse(value: ValueRange): List<QuestEntry> {
|
||||
val sheet = value.values.sheet()
|
||||
lateinit var structure: Map<String, Int>
|
||||
|
||||
return sheet?.mapIndexedNotNull { index, item ->
|
||||
when {
|
||||
index == 0 -> {
|
||||
structure = item.checkSheetStructure(model = COLUMNS)
|
||||
null
|
||||
}
|
||||
|
||||
item is List<*> -> {
|
||||
val title = item.getOrNull(structure.title) as? String
|
||||
val subtitle = item.getOrNull(structure.subtitle) as? String?
|
||||
val complete = item.getOrNull(structure.complete) as? String?
|
||||
val questGiver = item.getOrNull(structure.questGiver) as? String?
|
||||
val area = item.getOrNull(structure.area) as? String?
|
||||
val groupReward = item.getOrNull(structure.groupReward) as? String?
|
||||
val individualReward = item.getOrNull(structure.individualReward) as? String?
|
||||
val description = item.getOrNull(structure.description) as? String
|
||||
val background = item.getOrNull(structure.background) as? String?
|
||||
|
||||
if (title?.isNotEmpty() == true && description?.isNotEmpty() == true) {
|
||||
QuestEntry(
|
||||
sheetIndex = index,
|
||||
title = title,
|
||||
subtitle = subtitle?.takeIf { it.isNotBlank() },
|
||||
complete = complete.equals("TRUE", ignoreCase = true),
|
||||
questGiver = questGiver?.takeIf { it.isNotBlank() },
|
||||
area = area?.takeIf { it.isNotBlank() },
|
||||
groupReward = groupReward?.takeIf { it.isNotBlank() },
|
||||
individualReward = individualReward?.takeIf { it.isNotBlank() },
|
||||
description = description,
|
||||
background = background?.toUriOrNull(),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private val Map<String, Int>.title: Int get() = getValue(COLUMNS[0])
|
||||
private val Map<String, Int>.subtitle: Int get() = getValue(COLUMNS[1])
|
||||
private val Map<String, Int>.complete: Int get() = getValue(COLUMNS[2])
|
||||
private val Map<String, Int>.questGiver: Int get() = getValue(COLUMNS[3])
|
||||
private val Map<String, Int>.area: Int get() = getValue(COLUMNS[4])
|
||||
private val Map<String, Int>.groupReward: Int get() = getValue(COLUMNS[5])
|
||||
private val Map<String, Int>.individualReward: Int get() = getValue(COLUMNS[6])
|
||||
private val Map<String, Int>.description: Int get() = getValue(COLUMNS[7])
|
||||
private val Map<String, Int>.background: Int get() = getValue(COLUMNS[8])
|
||||
|
||||
companion object {
|
||||
private val COLUMNS = listOf(
|
||||
"Titre",
|
||||
"Sous Titre",
|
||||
"Compléter",
|
||||
"Commanditaire",
|
||||
"Lieu",
|
||||
"Récompense de groupe",
|
||||
"Récompense individuelle",
|
||||
"Description",
|
||||
"fond"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.pixelized.rplexicon.facotry
|
||||
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import javax.inject.Inject
|
||||
|
||||
class RaceParser @Inject constructor() {
|
||||
|
||||
fun parser(race: String?): Lexicon.Race {
|
||||
return when (race?.takeIf { it.isNotBlank() }) {
|
||||
Race.ELF -> Lexicon.Race.ELF
|
||||
Race.HALFLING -> Lexicon.Race.HALFLING
|
||||
Race.HUMAN -> Lexicon.Race.HUMAN
|
||||
Race.DWARF -> Lexicon.Race.DWARF
|
||||
Race.HALF_ELF -> Lexicon.Race.HALF_ELF
|
||||
Race.HALF_ORC -> Lexicon.Race.HALF_ORC
|
||||
Race.DRAGONBORN -> Lexicon.Race.DRAGONBORN
|
||||
Race.GNOME -> Lexicon.Race.GNOME
|
||||
Race.TIEFLING -> Lexicon.Race.TIEFLING
|
||||
Race.AARAKOCRA -> Lexicon.Race.AARAKOCRA
|
||||
Race.GENASI -> Lexicon.Race.GENASI
|
||||
Race.DEEP_GNOME -> Lexicon.Race.DEEP_GNOME
|
||||
Race.GOLIATH -> Lexicon.Race.GOLIATH
|
||||
else -> Lexicon.Race.UNDETERMINED
|
||||
}
|
||||
}
|
||||
|
||||
private object Race {
|
||||
const val ELF = "Elfe"
|
||||
const val HALFLING = "Halfelin"
|
||||
const val HUMAN = "Humain"
|
||||
const val DWARF = "Nain"
|
||||
const val HALF_ELF = "Demi-Elfe"
|
||||
const val HALF_ORC = "Demi-Orc"
|
||||
const val DRAGONBORN = "Drakéide"
|
||||
const val GNOME = "Gnome"
|
||||
const val TIEFLING = "Tieffelin"
|
||||
const val AARAKOCRA = "Aarakocra"
|
||||
const val GENASI = "Génasi"
|
||||
const val DEEP_GNOME = "Gnome des Profondeurs"
|
||||
const val GOLIATH = "Goliath"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.pixelized.rplexicon.facotry
|
||||
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.model.Roll
|
||||
import javax.inject.Inject
|
||||
|
||||
class RollParser @Inject constructor() {
|
||||
private val diceRegex = Regex("(\\d+)d(\\d+)")
|
||||
private val bonusRegex = Regex("(?:[a-zA-Z]|\\?)[a-zA-Z]+")
|
||||
|
||||
fun parseRoll(characterSheet: CharacterSheet, value: String?): Roll {
|
||||
val roll = value?.split(";")
|
||||
|
||||
val label = roll?.getOrNull(0)
|
||||
val (dices, bonus) = roll?.getOrNull(1)?.let { item ->
|
||||
val dices = diceRegex.findAll(item).toList().map { it.parseDice() }
|
||||
val bonus = bonusRegex.findAll(item).map { bonus ->
|
||||
Roll.Bonus(
|
||||
label = bonus.value,
|
||||
bonus = bonus.value.parseBonus(characterSheet = characterSheet),
|
||||
)
|
||||
}
|
||||
dices.toList() to bonus.toList()
|
||||
} ?: (null to null)
|
||||
|
||||
return Roll(
|
||||
label = label.toString(),
|
||||
dices = dices ?: emptyList(),
|
||||
bonus = bonus ?: emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun String?.parseBonus(
|
||||
characterSheet: CharacterSheet,
|
||||
): Int = when (this?.lowercase()) {
|
||||
"bonus" -> characterSheet.proficiency
|
||||
"force" -> characterSheet.strengthBonus
|
||||
else -> 0
|
||||
}
|
||||
|
||||
private fun MatchResult.parseDice(): Roll.Dice {
|
||||
val (count, faces) = destructured
|
||||
return Roll.Dice(
|
||||
label = value,
|
||||
count = count.toIntOrNull() ?: 0,
|
||||
faces = faces.toIntOrNull() ?: 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package com.pixelized.rplexicon.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
|
||||
@Stable
|
||||
data class CharacterSheet(
|
||||
val hitPoint: Int, // Point de vie
|
||||
val armorClass: Int, // Classe d'armure
|
||||
val proficiency: Int, // Bonus de maîtrise
|
||||
val strength: Int, // Force
|
||||
val dexterity: Int, // Dextérité
|
||||
val constitution: Int, // Constitution
|
||||
val intelligence: Int, // Intelligence
|
||||
val wisdom: Int, // Sagesse
|
||||
val charisma: Int, // Charisme
|
||||
val strengthSavingThrows: Int, // Jet de sauvegarde: Force
|
||||
val dexteritySavingThrows: Int, // Jet de sauvegarde: Dextérité
|
||||
val constitutionSavingThrows: Int, // Jet de sauvegarde: Constitution
|
||||
val intelligenceSavingThrows: Int, // Jet de sauvegarde: Intelligence
|
||||
val wisdomSavingThrows: Int, // Jet de sauvegarde: Sagesse
|
||||
val charismaSavingThrows: Int, // Jet de sauvegarde: Charisme
|
||||
val acrobatics: Int, // DEX, Acrobaties
|
||||
val animalHandling: Int, // WIS, Arcanes
|
||||
val arcana: Int, // INT, Athlétisme
|
||||
val athletics: Int, // STR, Discrétion
|
||||
val deception: Int, // CHA, Dressage
|
||||
val history: Int, // INT, Escamotage
|
||||
val insight: Int, // WIS, Histoire
|
||||
val intimidation: Int, // CHA, Intimidation
|
||||
val investigation: Int, // INT, Intuition
|
||||
val medicine: Int, // WIS, Investigation
|
||||
val nature: Int, // INT, Médecine
|
||||
val perception: Int, // WIS, Nature
|
||||
val performance: Int, // CHA, Perception
|
||||
val persuasion: Int, // CHA, Persuasion
|
||||
val religion: Int, // INT, Religion
|
||||
val sleightOfHand: Int, // DEX, Représentation
|
||||
val stealth: Int, // DEX, Survie
|
||||
val survival: Int, // WIS, Tromperie
|
||||
) {
|
||||
val proficiencyBonus: Int = kotlin.math.floor(proficiency / 2 - 5f).toInt()
|
||||
val strengthBonus: Int = kotlin.math.floor(strength / 2 - 5f).toInt()
|
||||
val dexterityBonus: Int = kotlin.math.floor(dexterity / 2 - 5f).toInt()
|
||||
val constitutionBonus: Int = kotlin.math.floor(constitution / 2 - 5f).toInt()
|
||||
val intelligenceBonus: Int = kotlin.math.floor(intelligence / 2 - 5f).toInt()
|
||||
}
|
||||
|
||||
@Stable
|
||||
data class Roll(
|
||||
val label: String,
|
||||
val dices: List<Dice>,
|
||||
val bonus: List<Bonus>,
|
||||
) {
|
||||
@Stable
|
||||
data class Dice(
|
||||
val label: String,
|
||||
val count: Int,
|
||||
val faces: Int,
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class Bonus(
|
||||
val label: String,
|
||||
val bonus: Int,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
22
app/src/main/java/com/pixelized/rplexicon/model/Location.kt
Normal file
22
app/src/main/java/com/pixelized/rplexicon/model/Location.kt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package com.pixelized.rplexicon.model
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Stable
|
||||
|
||||
@Stable
|
||||
data class Location(
|
||||
val id: Int,
|
||||
val sheetIndex: Int,
|
||||
val name: String,
|
||||
val uri: Uri,
|
||||
val marquees: List<Marquee>,
|
||||
) {
|
||||
@Stable
|
||||
data class Marquee(
|
||||
val map: String,
|
||||
val name: String,
|
||||
val x: Float,
|
||||
val y: Float,
|
||||
val description: String?,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package com.pixelized.rplexicon.repository
|
||||
|
||||
import android.util.Log
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.facotry.RollParser
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.ServiceNotReady
|
||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class CharacterSheetRepository @Inject constructor(
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val rollParser: RollParser,
|
||||
) {
|
||||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchCharacterSheet() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.CHARACTER_SHEET)
|
||||
val data = request.execute()
|
||||
updateData(data = data)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
private fun updateData(data: ValueRange?) {
|
||||
val sheet = data?.values?.sheet()
|
||||
var id = 0
|
||||
|
||||
val bru = sheet?.map { (it as? List<*>)?.get(1) }
|
||||
|
||||
val characterSheet = CharacterSheet(
|
||||
hitPoint = (bru?.get(Sheet.HIT_POINT) as? String)?.toIntOrNull() ?: 0,
|
||||
armorClass = (bru?.get(Sheet.ARMOR_CLASS) as? String)?.toIntOrNull() ?: 0,
|
||||
proficiency = (bru?.get(Sheet.PROFICIENCY) as? String)?.toIntOrNull() ?: 0,
|
||||
strength = (bru?.get(Sheet.STRENGTH) as? String)?.toIntOrNull() ?: 0,
|
||||
dexterity = (bru?.get(Sheet.DEXTERITY) as? String)?.toIntOrNull() ?: 0,
|
||||
constitution = (bru?.get(Sheet.CONSTITUTION) as? String)?.toIntOrNull() ?: 0,
|
||||
intelligence = (bru?.get(Sheet.INTELLIGENCE) as? String)?.toIntOrNull() ?: 0,
|
||||
wisdom = (bru?.get(Sheet.WISDOM) as? String)?.toIntOrNull() ?: 0,
|
||||
charisma = (bru?.get(Sheet.CHARISMA) as? String)?.toIntOrNull() ?: 0,
|
||||
strengthSavingThrows = (bru?.get(Sheet.STRENGTH_SAVING_THROWS) as? String)?.toIntOrNull() ?: 0,
|
||||
dexteritySavingThrows = (bru?.get(Sheet.DEXTERITY_SAVING_THROWS) as? String)?.toIntOrNull() ?: 0,
|
||||
constitutionSavingThrows = (bru?.get(Sheet.CONSTITUTION_SAVING_THROWS) as? String)?.toIntOrNull() ?: 0,
|
||||
intelligenceSavingThrows = (bru?.get(Sheet.INTELLIGENCE_SAVING_THROWS) as? String)?.toIntOrNull() ?: 0,
|
||||
wisdomSavingThrows = (bru?.get(Sheet.WISDOM_SAVING_THROWS) as? String)?.toIntOrNull() ?: 0,
|
||||
charismaSavingThrows = (bru?.get(Sheet.CHARISMA_SAVING_THROWS) as? String)?.toIntOrNull() ?: 0,
|
||||
acrobatics = (bru?.get(Sheet.ACROBATICS) as? String)?.toIntOrNull() ?: 0,
|
||||
animalHandling = (bru?.get(Sheet.ANIMAL_HANDLING) as? String)?.toIntOrNull() ?: 0,
|
||||
arcana = (bru?.get(Sheet.ARCANA) as? String)?.toIntOrNull() ?: 0,
|
||||
athletics = (bru?.get(Sheet.ATHLETICS) as? String)?.toIntOrNull() ?: 0,
|
||||
deception = (bru?.get(Sheet.DECEPTION) as? String)?.toIntOrNull() ?: 0,
|
||||
history = (bru?.get(Sheet.HISTORY) as? String)?.toIntOrNull() ?: 0,
|
||||
insight = (bru?.get(Sheet.INSIGHT) as? String)?.toIntOrNull() ?: 0,
|
||||
intimidation = (bru?.get(Sheet.INTIMIDATION) as? String)?.toIntOrNull() ?: 0,
|
||||
investigation = (bru?.get(Sheet.INVESTIGATION) as? String)?.toIntOrNull() ?: 0,
|
||||
medicine = (bru?.get(Sheet.MEDICINE) as? String)?.toIntOrNull() ?: 0,
|
||||
nature = (bru?.get(Sheet.NATURE) as? String)?.toIntOrNull() ?: 0,
|
||||
perception = (bru?.get(Sheet.PERCEPTION) as? String)?.toIntOrNull() ?: 0,
|
||||
performance = (bru?.get(Sheet.PERFORMANCE) as? String)?.toIntOrNull() ?: 0,
|
||||
persuasion = (bru?.get(Sheet.PERSUASION) as? String)?.toIntOrNull() ?: 0,
|
||||
religion = (bru?.get(Sheet.RELIGION) as? String)?.toIntOrNull() ?: 0,
|
||||
sleightOfHand = (bru?.get(Sheet.SLEIGHT_OF_HAND) as? String)?.toIntOrNull() ?: 0,
|
||||
stealth = (bru?.get(Sheet.STEALTH) as? String)?.toIntOrNull() ?: 0,
|
||||
survival = (bru?.get(Sheet.SURVIVAL) as? String)?.toIntOrNull() ?: 0,
|
||||
)
|
||||
|
||||
val rolls = bru?.subList(fromIndex = 34, bru.size)?.mapNotNull {
|
||||
rollParser.parseRoll(characterSheet = characterSheet, value = it?.toString())
|
||||
}
|
||||
|
||||
Log.e(TAG, characterSheet.toString())
|
||||
Log.e(TAG, rolls.toString())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "CharacterSheetRepository"
|
||||
}
|
||||
|
||||
private object Sheet {
|
||||
const val ID = "1fHfzeb8y5u9lEQB1iI-jBEhqu7YSip5sAajXcXK7VJ8"
|
||||
const val CHARACTER_SHEET = "Feuille de personnage"
|
||||
|
||||
const val HIT_POINT = 1
|
||||
const val ARMOR_CLASS = 2
|
||||
const val PROFICIENCY = 3
|
||||
const val STRENGTH = 4
|
||||
const val DEXTERITY = 5
|
||||
const val CONSTITUTION = 6
|
||||
const val INTELLIGENCE = 7
|
||||
const val WISDOM = 8
|
||||
const val CHARISMA = 9
|
||||
const val STRENGTH_SAVING_THROWS = 10
|
||||
const val DEXTERITY_SAVING_THROWS = 11
|
||||
const val CONSTITUTION_SAVING_THROWS = 12
|
||||
const val INTELLIGENCE_SAVING_THROWS = 13
|
||||
const val WISDOM_SAVING_THROWS = 14
|
||||
const val CHARISMA_SAVING_THROWS = 15
|
||||
const val ACROBATICS = 16
|
||||
const val ANIMAL_HANDLING = 17
|
||||
const val ARCANA = 18
|
||||
const val ATHLETICS = 19
|
||||
const val DECEPTION = 20
|
||||
const val HISTORY = 21
|
||||
const val INSIGHT = 22
|
||||
const val INTIMIDATION = 23
|
||||
const val INVESTIGATION = 24
|
||||
const val MEDICINE = 25
|
||||
const val NATURE = 26
|
||||
const val PERCEPTION = 27
|
||||
const val PERFORMANCE = 28
|
||||
const val PERSUASION = 29
|
||||
const val RELIGION = 30
|
||||
const val SLEIGHT_OF_HAND = 31
|
||||
const val STEALTH = 32
|
||||
const val SURVIVAL = 33
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.pixelized.rplexicon.repository
|
||||
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import com.google.api.client.extensions.android.http.AndroidHttp
|
||||
import com.google.api.client.json.gson.GsonFactory
|
||||
import com.google.api.services.sheets.v4.Sheets
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.ServiceNotReady
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GoogleSheetServiceRepository @Inject constructor(
|
||||
authenticationRepository: AuthenticationRepository,
|
||||
) {
|
||||
private val service: Sheets? by derivedStateOf {
|
||||
when (authenticationRepository.isAuthenticated.value) {
|
||||
true -> Sheets
|
||||
.Builder(
|
||||
AndroidHttp.newCompatibleTransport(),
|
||||
GsonFactory(),
|
||||
authenticationRepository.credential,
|
||||
)
|
||||
.build()
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ServiceNotReady::class)
|
||||
suspend fun fetch(
|
||||
lambda: suspend CoroutineScope.(service: Sheets.Spreadsheets.Values) -> Unit,
|
||||
) {
|
||||
when (val service = service) {
|
||||
null -> throw ServiceNotReady()
|
||||
else -> withContext(Dispatchers.IO) {
|
||||
lambda(service.spreadsheets().values())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +1,20 @@
|
|||
package com.pixelized.rplexicon.repository
|
||||
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import com.google.api.client.extensions.android.http.AndroidHttp
|
||||
import com.google.api.client.json.gson.GsonFactory
|
||||
import com.google.api.services.sheets.v4.Sheets
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.facotry.LexiconParser
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.ServiceNotReady
|
||||
import com.pixelized.rplexicon.utilitary.extentions.checkSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||
import com.pixelized.rplexicon.utilitary.extentions.toUriOrNull
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class LexiconRepository @Inject constructor(
|
||||
private val authenticationRepository: AuthenticationRepository
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val lexiconParser: LexiconParser,
|
||||
) {
|
||||
private val sheetService: Sheets? by derivedStateOf {
|
||||
when (authenticationRepository.isAuthenticated.value) {
|
||||
true -> Sheets
|
||||
.Builder(
|
||||
AndroidHttp.newCompatibleTransport(),
|
||||
GsonFactory(),
|
||||
authenticationRepository.credential,
|
||||
)
|
||||
.build()
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private val _data = MutableStateFlow<List<Lexicon>>(emptyList())
|
||||
val data: StateFlow<List<Lexicon>> get() = _data
|
||||
|
||||
|
|
@ -46,156 +24,25 @@ class LexiconRepository @Inject constructor(
|
|||
|
||||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchLexicon() {
|
||||
val service = sheetService
|
||||
if (service == null) {
|
||||
throw ServiceNotReady()
|
||||
} else {
|
||||
withContext(Dispatchers.IO) {
|
||||
val request = service.spreadsheets().values().get(Sheet.ID, Sheet.LEXIQUE)
|
||||
val data = request.execute()
|
||||
updateData(data = data)
|
||||
}
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.LEXICON)
|
||||
val data = request.execute()
|
||||
updateData(data = data)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
private fun updateData(data: ValueRange?) {
|
||||
val sheet = data?.values?.sheet()
|
||||
var sheetStructure: Map<String, Int>? = null
|
||||
var id = 0
|
||||
val lexicon: List<Lexicon> = sheet?.mapIndexedNotNull { index, row ->
|
||||
when {
|
||||
index == 0 -> {
|
||||
sheetStructure = row.checkSheetStructure(model = Sheet.COLUMNS)
|
||||
null
|
||||
}
|
||||
|
||||
row is List<*> -> parseCharacterRow(
|
||||
sheetStructure = sheetStructure,
|
||||
id = id,
|
||||
sheetIndex = index,
|
||||
row = row,
|
||||
)?.also {
|
||||
// update next id if parsing is successful.
|
||||
id = it.id + 1
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
} ?: emptyList()
|
||||
private fun updateData(data: ValueRange) {
|
||||
val lexicon = lexiconParser.parse(data)
|
||||
_data.tryEmit(lexicon)
|
||||
}
|
||||
|
||||
private fun parseCharacterRow(
|
||||
sheetStructure: Map<String, Int>?,
|
||||
id: Int,
|
||||
sheetIndex: Int,
|
||||
row: List<*>?,
|
||||
): Lexicon? {
|
||||
val name = row?.getOrNull(sheetStructure.name) as? String
|
||||
val diminutive = row?.getOrNull(sheetStructure.diminutive) as? String?
|
||||
val gender = row?.getOrNull(sheetStructure.gender) as? String?
|
||||
val race = row?.getOrNull(sheetStructure.race) as? String?
|
||||
val portrait = row?.getOrNull(sheetStructure.portrait) as? String?
|
||||
val description = row?.getOrNull(sheetStructure.description) as? String?
|
||||
val history = row?.getOrNull(sheetStructure.history) as? String?
|
||||
val tags = row?.getOrNull(sheetStructure.tags) as? String?
|
||||
|
||||
return if (name != null) {
|
||||
Lexicon(
|
||||
id = id,
|
||||
sheetIndex = sheetIndex,
|
||||
name = name,
|
||||
diminutive = diminutive?.takeIf { it.isNotBlank() },
|
||||
gender = when (gender?.takeIf { it.isNotBlank() }) {
|
||||
Gender.MALE -> Lexicon.Gender.MALE
|
||||
Gender.FEMALE -> Lexicon.Gender.FEMALE
|
||||
else -> Lexicon.Gender.UNDETERMINED
|
||||
},
|
||||
race = when (race?.takeIf { it.isNotBlank() }) {
|
||||
Race.ELF -> Lexicon.Race.ELF
|
||||
Race.HALFLING -> Lexicon.Race.HALFLING
|
||||
Race.HUMAN -> Lexicon.Race.HUMAN
|
||||
Race.DWARF -> Lexicon.Race.DWARF
|
||||
Race.HALF_ELF -> Lexicon.Race.HALF_ELF
|
||||
Race.HALF_ORC -> Lexicon.Race.HALF_ORC
|
||||
Race.DRAGONBORN -> Lexicon.Race.DRAGONBORN
|
||||
Race.GNOME -> Lexicon.Race.GNOME
|
||||
Race.TIEFLING -> Lexicon.Race.TIEFLING
|
||||
Race.AARAKOCRA -> Lexicon.Race.AARAKOCRA
|
||||
Race.GENASI -> Lexicon.Race.GENASI
|
||||
Race.DEEP_GNOME -> Lexicon.Race.DEEP_GNOME
|
||||
Race.GOLIATH -> Lexicon.Race.GOLIATH
|
||||
else -> Lexicon.Race.UNDETERMINED
|
||||
},
|
||||
portrait = portrait?.split("\n")?.mapNotNull { it.toUriOrNull() } ?: emptyList(),
|
||||
description = description?.takeIf { it.isNotBlank() },
|
||||
history = history?.takeIf { it.isNotBlank() },
|
||||
tags = tags?.takeIf { it.isNotBlank() },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private val Map<String, Int>?.name: Int get() = this?.getValue(Sheet.NAME) ?: 0
|
||||
private val Map<String, Int>?.diminutive: Int get() = this?.getValue(Sheet.DIMINUTIVE) ?: 1
|
||||
private val Map<String, Int>?.gender: Int get() = this?.getValue(Sheet.GENDER) ?: 2
|
||||
private val Map<String, Int>?.race: Int get() = this?.getValue(Sheet.RACE) ?: 3
|
||||
private val Map<String, Int>?.portrait: Int get() = this?.getValue(Sheet.PORTRAIT) ?: 4
|
||||
private val Map<String, Int>?.description: Int get() = this?.getValue(Sheet.DESCRIPTION) ?: 5
|
||||
private val Map<String, Int>?.history: Int get() = this?.getValue(Sheet.HISTORY) ?: 6
|
||||
private val Map<String, Int>?.tags: Int get() = this?.getValue(Sheet.TAGS) ?: 7
|
||||
|
||||
companion object {
|
||||
const val TAG = "LexiconRepository"
|
||||
}
|
||||
|
||||
private object Sheet {
|
||||
const val ID = "1oL9Nu5y37BPEbKxHre4TN9o8nrgy2JQoON4RRkdAHMs"
|
||||
|
||||
const val LEXIQUE = "Lexique"
|
||||
const val META = "MetaData"
|
||||
|
||||
val COLUMNS = listOf(
|
||||
"Nom",
|
||||
"Diminutif",
|
||||
"Sexe",
|
||||
"Race",
|
||||
"Portrait",
|
||||
"Description",
|
||||
"Histoire",
|
||||
"Mots clés",
|
||||
)
|
||||
|
||||
val NAME = COLUMNS[0]
|
||||
val DIMINUTIVE = COLUMNS[1]
|
||||
val GENDER = COLUMNS[2]
|
||||
val RACE = COLUMNS[3]
|
||||
val PORTRAIT = COLUMNS[4]
|
||||
val DESCRIPTION = COLUMNS[5]
|
||||
val HISTORY = COLUMNS[6]
|
||||
val TAGS = COLUMNS[7]
|
||||
}
|
||||
|
||||
private object Gender {
|
||||
const val MALE = "Male"
|
||||
const val FEMALE = "Femelle"
|
||||
}
|
||||
|
||||
private object Race {
|
||||
const val ELF = "Elfe"
|
||||
const val HALFLING = "Halfelin"
|
||||
const val HUMAN = "Humain"
|
||||
const val DWARF = "Nain"
|
||||
const val HALF_ELF = "Demi-Elfe"
|
||||
const val HALF_ORC = "Demi-Orc"
|
||||
const val DRAGONBORN = "Drakéide"
|
||||
const val GNOME = "Gnome"
|
||||
const val TIEFLING = "Tieffelin"
|
||||
const val AARAKOCRA = "Aarakocra"
|
||||
const val GENASI = "Génasi"
|
||||
const val DEEP_GNOME = "Gnome des Profondeurs"
|
||||
const val GOLIATH = "Goliath"
|
||||
const val LEXICON = "Lexique"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.pixelized.rplexicon.repository
|
||||
|
||||
import com.google.api.services.sheets.v4.Sheets
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.facotry.LocationParser
|
||||
import com.pixelized.rplexicon.facotry.MarqueeParser
|
||||
import com.pixelized.rplexicon.model.Location
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.ServiceNotReady
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class LocationRepository @Inject constructor(
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val locationParser: LocationParser,
|
||||
private val marqueeParser: MarqueeParser,
|
||||
) {
|
||||
private val _data = MutableStateFlow<List<Location>>(emptyList())
|
||||
val data: StateFlow<List<Location>> get() = _data
|
||||
|
||||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchLocation() {
|
||||
googleRepository.fetch { sheet: Sheets.Spreadsheets.Values ->
|
||||
val (map, marquee) = awaitAll(
|
||||
async { sheet.get(Sheet.ID, Sheet.MAP).execute() },
|
||||
async { sheet.get(Sheet.ID, Sheet.MARQUEE).execute() },
|
||||
)
|
||||
updateData(map = map, marquee = marquee)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
private fun updateData(map: ValueRange, marquee: ValueRange) {
|
||||
val marquees = marqueeParser
|
||||
.parse(data = marquee)
|
||||
.groupBy { it.map }
|
||||
|
||||
val maps = locationParser
|
||||
.parse(data = map)
|
||||
.map {
|
||||
val associatedMarquees = marquees[it.name]
|
||||
if (associatedMarquees != null) {
|
||||
it.copy(marquees = associatedMarquees)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
_data.tryEmit(maps)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "LocationRepository"
|
||||
}
|
||||
|
||||
private object Sheet {
|
||||
const val ID = "1gbWaqXChz8pDJ-O3-Q8a_0wbDAYGlVA2voL7nEJUSn0"
|
||||
const val MAP = "carte"
|
||||
const val MARQUEE = "marqueur"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +1,35 @@
|
|||
package com.pixelized.rplexicon.repository
|
||||
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import com.google.api.client.extensions.android.http.AndroidHttp
|
||||
import com.google.api.client.json.gson.GsonFactory
|
||||
import com.google.api.services.sheets.v4.Sheets
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.facotry.QuestParser
|
||||
import com.pixelized.rplexicon.model.Quest
|
||||
import com.pixelized.rplexicon.model.QuestEntry
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.ServiceNotReady
|
||||
import com.pixelized.rplexicon.utilitary.extentions.checkSheetStructure
|
||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||
import com.pixelized.rplexicon.utilitary.extentions.toUriOrNull
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class QuestRepository @Inject constructor(
|
||||
private val authenticationRepository: AuthenticationRepository,
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val questParser: QuestParser,
|
||||
) {
|
||||
private val sheetService: Sheets? by derivedStateOf {
|
||||
when (authenticationRepository.isAuthenticated.value) {
|
||||
true -> Sheets
|
||||
.Builder(
|
||||
AndroidHttp.newCompatibleTransport(),
|
||||
GsonFactory(),
|
||||
authenticationRepository.credential,
|
||||
)
|
||||
.build()
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private val _data = MutableStateFlow<List<Quest>>(emptyList())
|
||||
val data: StateFlow<List<Quest>> get() = _data
|
||||
|
||||
@Throws(ServiceNotReady::class, IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchQuests() {
|
||||
val service = sheetService
|
||||
if (service == null) {
|
||||
throw ServiceNotReady()
|
||||
} else {
|
||||
withContext(Dispatchers.IO) {
|
||||
val request = service.spreadsheets().values().get(Sheet.ID, Sheet.QUEST_JOURNAL)
|
||||
val data = request.execute()
|
||||
updateData(data = data)
|
||||
}
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(Sheet.ID, Sheet.QUEST_JOURNAL)
|
||||
val data = request.execute()
|
||||
updateData(data = data)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
private fun updateData(data: ValueRange?) {
|
||||
val sheet = data?.values?.sheet()
|
||||
var sheetStructure: Map<String, Int>? = null
|
||||
|
||||
val questEntries: List<QuestEntry> = sheet?.mapIndexedNotNull { index, row ->
|
||||
when {
|
||||
index == 0 -> {
|
||||
sheetStructure = row.checkSheetStructure(model = Sheet.COLUMNS)
|
||||
null
|
||||
}
|
||||
|
||||
row is List<*> -> parseQuestRow(
|
||||
sheetStructure = sheetStructure,
|
||||
sheetIndex = index,
|
||||
row = row,
|
||||
)
|
||||
|
||||
else -> null
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
private fun updateData(data: ValueRange) {
|
||||
val questEntries = questParser.parse(value = data)
|
||||
val questMap = questEntries.groupBy { it.title }
|
||||
|
||||
val quests = questMap.keys.mapIndexed { index, item ->
|
||||
|
|
@ -86,77 +39,11 @@ class QuestRepository @Inject constructor(
|
|||
entries = questMap[item] ?: emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
_data.tryEmit(quests)
|
||||
}
|
||||
|
||||
private fun parseQuestRow(
|
||||
sheetStructure: Map<String, Int>?,
|
||||
sheetIndex: Int,
|
||||
row: List<*>?,
|
||||
): QuestEntry? {
|
||||
val title = row?.getOrNull(sheetStructure.title) as? String
|
||||
val subtitle = row?.getOrNull(sheetStructure.subtitle) as? String?
|
||||
val complete = row?.getOrNull(sheetStructure.complete) as? String?
|
||||
val questGiver = row?.getOrNull(sheetStructure.questGiver) as? String?
|
||||
val area = row?.getOrNull(sheetStructure.area) as? String?
|
||||
val groupReward = row?.getOrNull(sheetStructure.groupReward) as? String?
|
||||
val individualReward = row?.getOrNull(sheetStructure.individualReward) as? String?
|
||||
val description = row?.getOrNull(sheetStructure.description) as? String
|
||||
val background = row?.getOrNull(sheetStructure.background) as? String?
|
||||
|
||||
return if (title?.isNotEmpty() == true && description?.isNotEmpty() == true) {
|
||||
QuestEntry(
|
||||
sheetIndex = sheetIndex,
|
||||
title = title,
|
||||
subtitle = subtitle?.takeIf { it.isNotBlank() },
|
||||
complete = complete.equals("TRUE", ignoreCase = true),
|
||||
questGiver = questGiver?.takeIf { it.isNotBlank() },
|
||||
area = area?.takeIf { it.isNotBlank() },
|
||||
groupReward = groupReward?.takeIf { it.isNotBlank() },
|
||||
individualReward = individualReward?.takeIf { it.isNotBlank() },
|
||||
description = description,
|
||||
background = background?.toUriOrNull(),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private val Map<String, Int>?.title: Int get() = this?.getValue(Sheet.TITLE) ?: 0
|
||||
private val Map<String, Int>?.subtitle: Int get() = this?.getValue(Sheet.SUBTITLE) ?: 1
|
||||
private val Map<String, Int>?.complete: Int get() = this?.getValue(Sheet.COMPLETE) ?: 2
|
||||
private val Map<String, Int>?.questGiver: Int get() = this?.getValue(Sheet.QUEST_GIVER) ?: 3
|
||||
private val Map<String, Int>?.area: Int get() = this?.getValue(Sheet.AREA) ?: 4
|
||||
private val Map<String, Int>?.groupReward: Int get() = this?.getValue(Sheet.G_REWARD) ?: 5
|
||||
private val Map<String, Int>?.individualReward: Int get() = this?.getValue(Sheet.I_REWARD) ?: 6
|
||||
private val Map<String, Int>?.description: Int get() = this?.getValue(Sheet.DESCRIPTION) ?: 7
|
||||
private val Map<String, Int>?.background: Int get() = this?.getValue(Sheet.BACKGROUND) ?: 8
|
||||
|
||||
private object Sheet {
|
||||
const val ID = "1sDAay8DjbRYKM39MvEXWs-RuvyxjOFpOfRZLAEWjIUY"
|
||||
|
||||
const val QUEST_JOURNAL = "Journal de quêtes"
|
||||
|
||||
val COLUMNS = listOf(
|
||||
"Titre",
|
||||
"Sous Titre",
|
||||
"Compléter",
|
||||
"Commanditaire",
|
||||
"Lieu",
|
||||
"Récompense de groupe",
|
||||
"Récompense individuelle",
|
||||
"Description",
|
||||
"fond"
|
||||
)
|
||||
val TITLE = COLUMNS[0]
|
||||
val SUBTITLE = COLUMNS[1]
|
||||
val COMPLETE = COLUMNS[2]
|
||||
val QUEST_GIVER = COLUMNS[3]
|
||||
val AREA = COLUMNS[4]
|
||||
val G_REWARD = COLUMNS[5]
|
||||
val I_REWARD = COLUMNS[6]
|
||||
val DESCRIPTION = COLUMNS[7]
|
||||
val BACKGROUND = COLUMNS[8]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue