From dc5e52cf180ee152e81674a94f388d1cea1ae181 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Mon, 31 Jul 2023 18:29:01 +0200 Subject: [PATCH] Add support for a tags data. --- .../com/pixelized/rplexicon/model/Lexicon.kt | 2 + .../rplexicon/repository/LexiconRepository.kt | 63 ++++++++++++------- .../screens/detail/CharacterDetailScreen.kt | 20 +++++- .../detail/CharacterDetailViewModel.kt | 1 + .../rplexicon/ui/screens/search/SearchItem.kt | 20 ++++++ .../ui/screens/search/SearchScreen.kt | 8 +-- .../ui/screens/search/SearchViewModel.kt | 4 +- app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 9 files changed, 92 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/pixelized/rplexicon/model/Lexicon.kt b/app/src/main/java/com/pixelized/rplexicon/model/Lexicon.kt index 2cf6423..383542f 100644 --- a/app/src/main/java/com/pixelized/rplexicon/model/Lexicon.kt +++ b/app/src/main/java/com/pixelized/rplexicon/model/Lexicon.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.Stable @Stable data class Lexicon( val id: Int, + val sheetIndex: Int, val name: String, val diminutive: String?, val gender: Gender, @@ -13,6 +14,7 @@ data class Lexicon( val portrait: List, val description: String?, val history: String?, + val tags: String?, ) { @Stable diff --git a/app/src/main/java/com/pixelized/rplexicon/repository/LexiconRepository.kt b/app/src/main/java/com/pixelized/rplexicon/repository/LexiconRepository.kt index 81f8394..7afac05 100644 --- a/app/src/main/java/com/pixelized/rplexicon/repository/LexiconRepository.kt +++ b/app/src/main/java/com/pixelized/rplexicon/repository/LexiconRepository.kt @@ -55,6 +55,7 @@ class LexiconRepository @Inject constructor( private fun updateData(data: ValueRange?) { val sheet = data?.values?.sheet() var sheetStructure: Map? = null + var id = 0 val lexicon: List = sheet?.mapIndexedNotNull { index, row -> when { index == 0 -> { @@ -64,9 +65,13 @@ class LexiconRepository @Inject constructor( row is List<*> -> parseCharacterRow( sheetStructure = sheetStructure, - index = index - 1, + id = id, + sheetIndex = index, row = row, - ) + )?.also { + // update next id if parsing is successful. + id = it.id + 1 + } else -> null } @@ -82,24 +87,19 @@ class LexiconRepository @Inject constructor( } // parse the first line to find element that we recognize. val sheetStructure = hashMapOf() + firstRow.forEachIndexed { index, cell -> - when (cell as? String) { - Sheet.NAME, - Sheet.DIMINUTIVE, - Sheet.GENDER, - Sheet.RACE, - Sheet.PORTRAIT, - Sheet.DESCRIPTION, - Sheet.HISTORY -> sheetStructure[cell] = index + if (cell is String && Sheet.COLUMNS.contains(cell)) { + sheetStructure[cell] = index } } // check if we found everything we need. when { - sheetStructure.size < Sheet.KNOWN_COLUMN -> throw IncompatibleSheetStructure( + sheetStructure.size < Sheet.COLUMNS.size -> throw IncompatibleSheetStructure( message = "Sheet header row does not have enough column: ${firstRow.size}.\nstructure: $firstRow\nheader: $sheetStructure" ) - sheetStructure.size > Sheet.KNOWN_COLUMN -> throw IncompatibleSheetStructure( + sheetStructure.size > Sheet.COLUMNS.size -> throw IncompatibleSheetStructure( message = "Sheet header row does have too mush columns: ${firstRow.size}.\nstructure: $firstRow\nheader: $sheetStructure" ) } @@ -109,7 +109,8 @@ class LexiconRepository @Inject constructor( private fun parseCharacterRow( sheetStructure: Map?, - index: Int, + id: Int, + sheetIndex: Int, row: List<*>?, ): Lexicon? { val name = row?.getOrNull(sheetStructure.name) as? String @@ -119,10 +120,12 @@ class LexiconRepository @Inject constructor( 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 = index, + id = id, + sheetIndex = sheetIndex, name = name, diminutive = diminutive?.takeIf { it.isNotBlank() }, gender = when (gender?.takeIf { it.isNotBlank() }) { @@ -149,6 +152,7 @@ class LexiconRepository @Inject constructor( 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 @@ -175,6 +179,7 @@ class LexiconRepository @Inject constructor( private val Map?.portrait: Int get() = this?.getValue(Sheet.PORTRAIT) ?: 4 private val Map?.description: Int get() = this?.getValue(Sheet.DESCRIPTION) ?: 5 private val Map?.history: Int get() = this?.getValue(Sheet.HISTORY) ?: 6 + private val Map?.tags: Int get() = this?.getValue(Sheet.TAGS) ?: 7 class ServiceNotReady : Exception() @@ -186,15 +191,29 @@ class LexiconRepository @Inject constructor( private object Sheet { const val ID = "1oL9Nu5y37BPEbKxHre4TN9o8nrgy2JQoON4RRkdAHMs" + const val LEXIQUE = "Lexique" - const val KNOWN_COLUMN = 7 - const val NAME = "Nom" - const val DIMINUTIVE = "Diminutif" - const val GENDER = "Sexe" - const val RACE = "Race" - const val PORTRAIT = "Portrait" - const val DESCRIPTION = "Description" - const val HISTORY = "Histoire" + 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 { diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/detail/CharacterDetailScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/detail/CharacterDetailScreen.kt index ce7cebd..74ea444 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/detail/CharacterDetailScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/detail/CharacterDetailScreen.kt @@ -80,6 +80,7 @@ data class CharacterDetailUio( val search: String?, val highlightGender: Boolean?, val highlightRace: Boolean?, + val tags: String?, ) @Stable @@ -91,6 +92,7 @@ data class AnnotatedCharacterDetailUio( val portrait: List, val description: AnnotatedString?, val history: AnnotatedString?, + val tags: AnnotatedString? ) @Composable @@ -104,6 +106,7 @@ fun CharacterDetailUio.annotated(): AnnotatedCharacterDetailUio { return remember(search, race, highlightRace, gender, highlightGender) { AnnotatedCharacterDetailUio( + portrait = portrait, name = AnnotatedString( text = name, spanStyles = highlightRegex?.annotatedSpan( @@ -137,7 +140,9 @@ fun CharacterDetailUio.annotated(): AnnotatedCharacterDetailUio { history = history?.let { history -> highlightRegex?.annotatedString(history, spanStyle = highlight) }, - portrait = portrait, + tags = tags?.let { tags -> + highlightRegex?.annotatedString(tags, spanStyle = highlight) + }, ) } } @@ -244,6 +249,7 @@ private fun CharacterDetailScreenContent( ) } } + Row( modifier = Modifier.padding(horizontal = 16.dp), horizontalArrangement = Arrangement.spacedBy(4.dp) @@ -257,6 +263,7 @@ private fun CharacterDetailScreenContent( text = annotatedItem.race, ) } + annotatedItem.description?.let { Text( modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp), @@ -276,6 +283,7 @@ private fun CharacterDetailScreenContent( text = it, ) } + annotatedItem.history?.let { Text( modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp), @@ -288,6 +296,7 @@ private fun CharacterDetailScreenContent( text = it, ) } + if (annotatedItem.portrait.isNotEmpty()) { val maxSize = rememberPortraitWidth() Text( @@ -316,6 +325,14 @@ private fun CharacterDetailScreenContent( } } } + + annotatedItem.tags?.let { + Text( + modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp), + style = remember { typography.labelSmall.copy(fontStyle = FontStyle.Italic) }, + text = it, + ) + } } } } @@ -374,6 +391,7 @@ private fun CharacterDetailScreenContentPreview() { ), description = "Brulkhai, ou plus simplement Bru, est solidement bâti. Elle mesure 192 cm pour 110 kg de muscles lorsqu’elle est en bonne santé. Elle a les cheveux châtains, les yeux noisettes et la peau couleur gris-vert typique de son espèce. D’un tempérament taciturne, elle parle peu et de façon concise. Elle est parfois brutale, aussi bien physiquement que verbalement, Elle ne prend cependant aucun plaisir à malmener ceux qu’elle considère plus faibles qu’elle. D’une nature simple et honnête, elle ne mâche pas ses mots et ne dissimule généralement pas ses pensées. Son intelligence modeste est plus le reflet d’un manque d’éducation et d’une capacité limitée à gérer ses émotions qu’à une débilité congénitale. Elle voue à la force un culte car c’est par son expression qu’elle se sent vraiment vivante et éprouve de grandes difficultés vis à vis de ceux qu’elle nomme foshnu (bébé, chouineur en commun).", history = null, + tags = null, search = "Bru", highlightGender = true, highlightRace = true, diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/detail/CharacterDetailViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/detail/CharacterDetailViewModel.kt index 9d017b7..60bd6b5 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/detail/CharacterDetailViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/detail/CharacterDetailViewModel.kt @@ -29,6 +29,7 @@ class CharacterDetailViewModel @Inject constructor( portrait = source.portrait, description = source.description, history = source.history, + tags = source.tags, search = argument.highlight, highlightGender = argument.highlightGender && argument.gender == source.gender, highlightRace = argument.highlightRace && argument.race == source.race, diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchItem.kt index 66eaf43..8dc9746 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchItem.kt @@ -48,6 +48,7 @@ class SearchItemUio( val race: Lexicon.Race, val description: String?, val history: String?, + val tags: String?, val search: String, val highlightGender: Boolean, val highlightRace: Boolean, @@ -75,6 +76,7 @@ class SearchItemUio( race = race, description = description, history = history, + tags = null, search = search, highlightGender = highlightGender, highlightRace = highlightRace, @@ -92,6 +94,7 @@ class AnnotatedSearchItemUio( val race: AnnotatedString, val description: AnnotatedString?, val history: AnnotatedString?, + val tags: AnnotatedString?, ) @Composable @@ -143,6 +146,9 @@ private fun SearchItemUio.annotate(): AnnotatedSearchItemUio { history = finderRegex?.foldAll(history)?.let { history -> highlightRegex?.annotatedString(history, spanStyle = highlight) }, + tags = finderRegex?.foldAll(tags)?.let { tags -> + highlightRegex?.annotatedString(tags, spanStyle = highlight) + } ) } } @@ -244,6 +250,20 @@ fun SearchItem( ) } } + annotatedItem.tags?.let { + Column( + modifier = Modifier.padding(start = 8.dp), + ) { + Text( + style = remember { typography.labelSmall.copy(fontWeight = FontWeight.Bold) }, + text = stringResource(id = R.string.search_item_tags), + ) + Text( + style = typography.labelSmall, + text = it, + ) + } + } } } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchScreen.kt index 54ed822..cc0b956 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchScreen.kt @@ -215,28 +215,28 @@ private fun SearchScreenContentPreview() { race = Lexicon.Race.HALF_ORC, ), SearchItemUio.preview( - id = 0, + id = 1, name = "Léandre", diminutive = null, gender = Lexicon.Gender.MALE, race = Lexicon.Race.HUMAN, ), SearchItemUio.preview( - id = 0, + id = 2, name = "Nélia", diminutive = null, gender = Lexicon.Gender.FEMALE, race = Lexicon.Race.ELF, ), SearchItemUio.preview( - id = 0, + id = 3, name = "Tigrane", diminutive = null, gender = Lexicon.Gender.MALE, race = Lexicon.Race.TIEFLING, ), SearchItemUio.preview( - id = 0, + id = 4, name = "Unathana", diminutive = "Una", gender = Lexicon.Gender.FEMALE, diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchViewModel.kt index 248847f..03538d7 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchViewModel.kt @@ -57,7 +57,8 @@ class SearchViewModel @Inject constructor( val diminutive = item.diminutive?.contains(search, true) == true val description = item.description?.contains(search, true) == true val history = item.history?.contains(search, true) == true - name || diminutive || description || history + val tag = item.tags?.contains(search, true) == true + name || diminutive || description || history || tag } (gender == null || gender) && (race == null || race) && (search == null || search) }.map { @@ -82,5 +83,6 @@ class SearchViewModel @Inject constructor( search = search, highlightGender = highlightGender, highlightRace = highlightRace, + tags = tags, ) } \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8ff55a4..42b78d5 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -41,4 +41,5 @@ Sexe Description : Histoire : + Mots clés : \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0390725..1e6e015 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -41,4 +41,5 @@ Gender Description: History: + Tags: \ No newline at end of file