Add support for a tags data.
This commit is contained in:
parent
82738a8f03
commit
dc5e52cf18
9 changed files with 92 additions and 28 deletions
|
|
@ -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<Uri>,
|
||||
val description: String?,
|
||||
val history: String?,
|
||||
val tags: String?,
|
||||
) {
|
||||
|
||||
@Stable
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class LexiconRepository @Inject constructor(
|
|||
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 -> {
|
||||
|
|
@ -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<String, Int>()
|
||||
|
||||
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<String, Int>?,
|
||||
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<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
|
||||
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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<Uri>,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -41,4 +41,5 @@
|
|||
<string name="search_field_gender">Sexe</string>
|
||||
<string name="search_item_description">Description :</string>
|
||||
<string name="search_item_history">Histoire :</string>
|
||||
<string name="search_item_tags">Mots clés :</string>
|
||||
</resources>
|
||||
|
|
@ -41,4 +41,5 @@
|
|||
<string name="search_field_gender">Gender</string>
|
||||
<string name="search_item_description">Description:</string>
|
||||
<string name="search_item_history">History:</string>
|
||||
<string name="search_item_tags">Tags:</string>
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue