Remove Int id from Quest

This commit is contained in:
Thomas Andres Gomez 2023-11-12 18:56:17 +01:00
parent 3880807372
commit 865b9abf5e
9 changed files with 57 additions and 51 deletions

View file

@ -5,7 +5,7 @@ import androidx.compose.runtime.Stable
@Stable @Stable
data class Quest( data class Quest(
val id: Int, val id: String,
val title: String, val title: String,
val entries: List<QuestEntry>, val entries: List<QuestEntry>,
) )

View file

@ -2,25 +2,26 @@ package com.pixelized.rplexicon.data.parser
import com.google.api.services.sheets.v4.model.ValueRange import com.google.api.services.sheets.v4.model.ValueRange
import com.pixelized.rplexicon.data.model.Quest
import com.pixelized.rplexicon.data.model.QuestEntry import com.pixelized.rplexicon.data.model.QuestEntry
import javax.inject.Inject import javax.inject.Inject
class QuestParser @Inject constructor( class QuestParser @Inject constructor(
private val imageParser: PortraitParser private val imageParser: PortraitParser
) { ) {
fun parse(sheet: ValueRange): List<QuestEntry> = parserScope { fun parse(sheet: ValueRange): List<Quest> = parserScope {
val quest = mutableListOf<QuestEntry>() val entries = hashMapOf<String, MutableList<QuestEntry>>()
sheet.forEachRowIndexed { index, item -> sheet.forEachRowIndexed { index, item ->
when (index) { when (index) {
0 -> updateStructure(row = item, columns = COLUMNS) 0 -> updateStructure(row = item, columns = COLUMNS)
else -> { else -> {
val title = item.parse(column = TITLE) val quest = item.parse(column = TITLE)
val description = item.parse(column = DESCRIPTION) val description = item.parse(column = DESCRIPTION)
if (title?.isNotEmpty() == true && description?.isNotEmpty() == true) { if (quest != null && description != null) {
val entry = QuestEntry( val entry = QuestEntry(
sheetIndex = index, sheetIndex = index,
title = title, title = quest,
subtitle = item.parse(column = SUB_TITLE), subtitle = item.parse(column = SUB_TITLE),
complete = item.parseBool(column = COMPLETED) ?: false, complete = item.parseBool(column = COMPLETED) ?: false,
questGiver = item.parse(column = QUEST_GIVER), questGiver = item.parse(column = QUEST_GIVER),
@ -31,13 +32,21 @@ class QuestParser @Inject constructor(
images = imageParser.parse(item.parse(column = IMAGE)), images = imageParser.parse(item.parse(column = IMAGE)),
background = item.parseUri(column = BACKGROUND), background = item.parseUri(column = BACKGROUND),
) )
quest.add(entry) entries.getOrPut(quest) { mutableListOf() }.add(entry)
} }
} }
} }
} }
return@parserScope quest val quests = entries.keys.map { quest ->
Quest(
id = "$quest-1", // TODO refactor that when quest have ids in the google sheet.
title = quest,
entries = entries[quest] ?: emptyList()
)
}
return@parserScope quests
} }
companion object { companion object {

View file

@ -24,8 +24,8 @@ class LocationRepository @Inject constructor(
var lastSuccessFullUpdate: Update = Update.INITIAL var lastSuccessFullUpdate: Update = Update.INITIAL
private set private set
fun find(id: String): Location? { fun find(id: String?): Location? {
return _data.value.firstOrNull { it.id == id } return id?.let { _data.value.firstOrNull { it.id == id } }
} }
@Throws(IncompatibleSheetStructure::class, Exception::class) @Throws(IncompatibleSheetStructure::class, Exception::class)

View file

@ -1,6 +1,5 @@
package com.pixelized.rplexicon.data.repository.lexicon package com.pixelized.rplexicon.data.repository.lexicon
import com.google.api.services.sheets.v4.model.ValueRange
import com.pixelized.rplexicon.data.model.Quest import com.pixelized.rplexicon.data.model.Quest
import com.pixelized.rplexicon.data.parser.QuestParser import com.pixelized.rplexicon.data.parser.QuestParser
import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository
@ -23,27 +22,17 @@ class QuestRepository @Inject constructor(
var lastSuccessFullUpdate: Update = Update.INITIAL var lastSuccessFullUpdate: Update = Update.INITIAL
private set private set
fun find(id: String?): Quest? {
return id?.let { data.value.firstOrNull { it.id == id } }
}
@Throws(IncompatibleSheetStructure::class, Exception::class) @Throws(IncompatibleSheetStructure::class, Exception::class)
suspend fun fetchQuests() { suspend fun fetchQuests() {
googleRepository.fetch { sheet -> googleRepository.fetch { sheet ->
val request = sheet.get(LexiconBinder.ID, LexiconBinder.QUEST_JOURNAL) val request = sheet.get(LexiconBinder.ID, LexiconBinder.QUEST_JOURNAL)
val data = request.execute() val quests = questParser.parse(sheet = request.execute())
updateData(data = data) _data.emit(quests)
lastSuccessFullUpdate = Update.currentTime() lastSuccessFullUpdate = Update.currentTime()
} }
} }
@Throws(IncompatibleSheetStructure::class, Exception::class)
private suspend fun updateData(data: ValueRange) {
val questEntries = questParser.parse(sheet = data)
val questMap = questEntries.groupBy { it.title }
val quests = questMap.keys.mapIndexed { index, item ->
Quest(
id = index,
title = item,
entries = questMap[item] ?: emptyList(),
)
}
_data.emit(quests)
}
} }

View file

@ -21,7 +21,7 @@ val QUEST_DETAIL_ROUTE = "$ROUTE?${ARG_ID.ARG}"
@Stable @Stable
@Immutable @Immutable
data class QuestDetailArgument( data class QuestDetailArgument(
val id: Int, val id: String,
) )
val SavedStateHandle.questDetailArgument: QuestDetailArgument val SavedStateHandle.questDetailArgument: QuestDetailArgument
@ -34,7 +34,7 @@ fun NavGraphBuilder.composableQuestDetail() {
route = QUEST_DETAIL_ROUTE, route = QUEST_DETAIL_ROUTE,
arguments = listOf( arguments = listOf(
navArgument(name = ARG_ID) { navArgument(name = ARG_ID) {
type = NavType.IntType type = NavType.StringType
}, },
), ),
animation = NavigationAnimation.Push, animation = NavigationAnimation.Push,
@ -44,7 +44,7 @@ fun NavGraphBuilder.composableQuestDetail() {
} }
fun NavHostController.navigateToQuestDetail( fun NavHostController.navigateToQuestDetail(
id: Int, id: String,
option: NavOptionsBuilder.() -> Unit = {}, option: NavOptionsBuilder.() -> Unit = {},
) { ) {
val route = "$ROUTE?$ARG_ID=$id" val route = "$ROUTE?$ARG_ID=$id"

View file

@ -62,7 +62,7 @@ import com.pixelized.rplexicon.utilitary.extentions.scrollOffset
@Stable @Stable
data class QuestDetailUio( data class QuestDetailUio(
val id: Int, val id: String,
val background: Uri?, val background: Uri?,
val completed: Boolean, val completed: Boolean,
val title: String, val title: String,
@ -110,7 +110,7 @@ fun QuestDetailScreen(
private fun QuestDetailContent( private fun QuestDetailContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
state: ScrollState = rememberScrollState(), state: ScrollState = rememberScrollState(),
item: State<QuestDetailUio>, item: State<QuestDetailUio?>,
onBack: () -> Unit, onBack: () -> Unit,
onGiver: (String) -> Unit, onGiver: (String) -> Unit,
onLocation: (String) -> Unit, onLocation: (String) -> Unit,
@ -149,9 +149,9 @@ private fun QuestDetailContent(
) { ) {
BackgroundImage( BackgroundImage(
modifier = Modifier.matchParentSize(), modifier = Modifier.matchParentSize(),
model = quest.background, model = quest?.background,
) )
if (quest.completed) { if (quest?.completed == true) {
Text( Text(
modifier = Modifier modifier = Modifier
.align(Alignment.TopEnd) .align(Alignment.TopEnd)
@ -168,8 +168,8 @@ private fun QuestDetailContent(
.verticalScroll(state) .verticalScroll(state)
.padding( .padding(
top = when { top = when {
quest.background == null && quest.completed -> 96.dp quest?.background == null && quest?.completed == true -> 96.dp
quest.background == null -> 16.dp quest?.background == null -> 16.dp
else -> MaterialTheme.lexicon.dimens.detailPadding else -> MaterialTheme.lexicon.dimens.detailPadding
}, },
bottom = 16.dp, bottom = 16.dp,
@ -184,12 +184,12 @@ private fun QuestDetailContent(
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
style = MaterialTheme.typography.headlineLarge, style = MaterialTheme.typography.headlineLarge,
text = annotateWithDropCap( text = annotateWithDropCap(
text = quest.title, text = quest?.title ?: "",
style = MaterialTheme.lexicon.typography.headlineLargeDropCap, style = MaterialTheme.lexicon.typography.headlineLargeDropCap,
), ),
) )
quest.steps.forEach { quest -> quest?.steps?.forEach { quest ->
Column( Column(
verticalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp),
) { ) {
@ -347,7 +347,7 @@ private class QuestDetailPreviewProvider : PreviewParameterProvider<State<QuestD
override val values: Sequence<State<QuestDetailUio>> = sequenceOf( override val values: Sequence<State<QuestDetailUio>> = sequenceOf(
mutableStateOf( mutableStateOf(
QuestDetailUio( QuestDetailUio(
id = 0, id = "La chasse aux loups",
completed = true, completed = true,
background = Uri.parse("https://as1.ftcdn.net/v2/jpg/05/50/22/58/1000_F_550225869_jAkLTRVb7ym7EHJYvDApVXQnpANvRd8O.jpg"), background = Uri.parse("https://as1.ftcdn.net/v2/jpg/05/50/22/58/1000_F_550225869_jAkLTRVb7ym7EHJYvDApVXQnpANvRd8O.jpg"),
title = "La chasse aux loups", title = "La chasse aux loups",
@ -369,7 +369,7 @@ private class QuestDetailPreviewProvider : PreviewParameterProvider<State<QuestD
), ),
mutableStateOf( mutableStateOf(
QuestDetailUio( QuestDetailUio(
id = 1, id = "Les enfants de la caravanes",
completed = false, completed = false,
background = Uri.parse("https://cdnb.artstation.com/p/assets/images/images/008/823/761/large/jon-pintar-adventurers-caravan-jon-pintar.jpg?1515529013"), background = Uri.parse("https://cdnb.artstation.com/p/assets/images/images/008/823/761/large/jon-pintar-adventurers-caravan-jon-pintar.jpg?1515529013"),
title = "Les enfants de la caravanes", title = "Les enfants de la caravanes",

View file

@ -18,25 +18,27 @@ class QuestDetailViewModel @Inject constructor(
lexiconRepository: LexiconRepository, lexiconRepository: LexiconRepository,
locationRepository: LocationRepository, locationRepository: LocationRepository,
) : ViewModel() { ) : ViewModel() {
val quest: State<QuestDetailUio> private val _quest = mutableStateOf<QuestDetailUio?>(null)
val quest: State<QuestDetailUio?> get() = _quest
init { init {
val argument = savedStateHandle.questDetailArgument val argument = savedStateHandle.questDetailArgument
val source = questRepository.data.value[argument.id] val source = questRepository.find(id = argument.id)
quest = mutableStateOf( if (source != null) {
QuestDetailUio( _quest.value = QuestDetailUio(
id = source.id, id = source.id,
completed = source.entries.all { it.complete }, completed = source.entries.all { it.complete },
background = source.entries.mapNotNull { it.background }.randomOrNull(), background = source.entries.mapNotNull { it.background }.randomOrNull(),
title = source.title, title = source.title,
steps = source.entries.map { entry -> steps = source.entries.map { entry ->
val location = locationRepository.find(id = entry.area)
QuestDetailUio.QuestStep( QuestDetailUio.QuestStep(
subtitle = entry.subtitle, subtitle = entry.subtitle,
giverId = lexiconRepository.findId(entry.questGiver), giverId = lexiconRepository.findId(entry.questGiver),
giver = entry.questGiver, giver = entry.questGiver,
placeId = entry.area, // TODO proper ID. placeId = location?.id,
place = entry.area, place = location?.name,
globalReward = entry.groupReward, globalReward = entry.groupReward,
individualReward = entry.individualReward, individualReward = entry.individualReward,
description = entry.description, description = entry.description,
@ -44,6 +46,6 @@ class QuestDetailViewModel @Inject constructor(
) )
}, },
) )
) }
} }
} }

View file

@ -28,14 +28,14 @@ import com.pixelized.rplexicon.utilitary.extentions.placeholder
@Stable @Stable
data class QuestItemUio( data class QuestItemUio(
val id: Int, val id: String,
val title: String, val title: String,
val complete: Boolean, val complete: Boolean,
val placeholder: Boolean = false, val placeholder: Boolean = false,
) { ) {
companion object { companion object {
fun preview( fun preview(
id: Int = 0, id: String = "La chasse aux loups",
title: String = "La chasse aux loups", title: String = "La chasse aux loups",
complete: Boolean = false, complete: Boolean = false,
placeHolder: Boolean = false, placeHolder: Boolean = false,

View file

@ -152,8 +152,14 @@ private fun QuestListPreview() {
items = remember { items = remember {
mutableStateOf( mutableStateOf(
listOf( listOf(
QuestItemUio.preview(id = 0, title = "La chasse aux loups"), QuestItemUio.preview(
QuestItemUio.preview(id = 1, title = "Les enfants de la caravanes"), id = "La chasse aux loups",
title = "La chasse aux loups",
),
QuestItemUio.preview(
id = "Les enfants de la caravanes",
title = "Les enfants de la caravanes",
),
) )
) )
}, },