Change the lexicons header layout and simplify it

This commit is contained in:
Thomas Andres Gomez 2023-11-16 16:26:27 +01:00
parent 012e8844cb
commit e7d8819f8c
17 changed files with 197 additions and 180 deletions

View file

@ -0,0 +1,54 @@
package com.pixelized.rplexicon.ui.composable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@Composable
fun CategoryHeader(
modifier: Modifier = Modifier,
text: String,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(space = 2.dp),
) {
Text(
style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Light,
text = text,
)
Box(
modifier = Modifier
.fillMaxWidth(0.5f)
.height(1.dp)
.background(brush = rememberHorizontalGradient())
)
}
}
@Stable
@Composable
private fun rememberHorizontalGradient(): Brush {
val colorScheme = MaterialTheme.colorScheme
return remember {
Brush.horizontalGradient(
colors = listOf(
colorScheme.onSurface.copy(alpha = 1f), Color.Transparent,
)
)
}
}

View file

@ -1,26 +0,0 @@
package com.pixelized.rplexicon.ui.screens.lexicon.list
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
@Stable
data class LexiconCategoryUio(
val title: String,
)
@Composable
fun LexiconCategory(
modifier: Modifier = Modifier,
item: LexiconCategoryUio,
) {
Text(
modifier = modifier,
style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Light,
text = item.title,
)
}

View file

@ -1,9 +0,0 @@
package com.pixelized.rplexicon.ui.screens.lexicon.list
import androidx.compose.runtime.Stable
@Stable
class LexiconGroupUio(
val category: LexiconCategoryUio?,
val items: List<LexiconItemUio>,
)

View file

@ -27,6 +27,13 @@ import com.pixelized.rplexicon.utilitary.LOS_HOLLOW
import com.pixelized.rplexicon.utilitary.extentions.cell import com.pixelized.rplexicon.utilitary.extentions.cell
import com.pixelized.rplexicon.utilitary.extentions.lexicon import com.pixelized.rplexicon.utilitary.extentions.lexicon
import com.pixelized.rplexicon.utilitary.extentions.placeholder import com.pixelized.rplexicon.utilitary.extentions.placeholder
import java.util.UUID
@Stable
class LexiconGroupUio(
val category: String?,
val items: List<LexiconItemUio>,
)
@Stable @Stable
data class LexiconItemUio( data class LexiconItemUio(
@ -39,23 +46,14 @@ data class LexiconItemUio(
val placeholder: Boolean = false, val placeholder: Boolean = false,
) { ) {
companion object { companion object {
@Stable fun placeholder() = LexiconItemUio(
fun preview( id = UUID.randomUUID().toString(),
id: String = "Brulkhai-1", name = "placeholder",
name: String = "Brulkhai", diminutive = null,
diminutive: String? = null, gender = null,
gender: String? = null, race = null,
race: String? = null, isPlayingCharacter = false,
isPlayingCharacter: Boolean = false, placeholder = true,
placeholder: Boolean = false,
) = LexiconItemUio(
id = id,
name = name,
diminutive = diminutive,
gender = gender,
race = race,
isPlayingCharacter = isPlayingCharacter,
placeholder = placeholder,
) )
} }
} }
@ -77,8 +75,7 @@ fun LexiconItem(
Text( Text(
modifier = Modifier modifier = Modifier
.padding(end = 4.dp) .padding(end = 4.dp)
.alignByBaseline() .alignByBaseline(),
.placeholder { item.placeholder },
style = typography.base.titleMedium, style = typography.base.titleMedium,
text = if (item.isPlayingCharacter) LOS_FULL else LOS_HOLLOW, text = if (item.isPlayingCharacter) LOS_FULL else LOS_HOLLOW,
) )
@ -166,19 +163,21 @@ private fun LexiconItemPreview(
private class LexiconItemPreviewProvider : PreviewParameterProvider<LexiconItemUio> { private class LexiconItemPreviewProvider : PreviewParameterProvider<LexiconItemUio> {
override val values: Sequence<LexiconItemUio> = sequenceOf( override val values: Sequence<LexiconItemUio> = sequenceOf(
LexiconItemUio.preview( LexiconItemUio(
id = "",
name = "Mundas-Naltum-Brulkhai-Arauishi", name = "Mundas-Naltum-Brulkhai-Arauishi",
diminutive = "Mun-Nalt-Bru-Arahi", diminutive = "Mun-Nalt-Bru-Arahi",
placeholder = false, gender = "Femme",
race = "Demi-orc",
isPlayingCharacter = true, isPlayingCharacter = true,
), ),
LexiconItemUio.preview( LexiconItemUio(
id = "",
name = "Brulkhai", name = "Brulkhai",
diminutive = "Bru", diminutive = "Bru",
placeholder = false, gender = "Femme",
), race = "Demi-orc",
LexiconItemUio.preview(
placeholder = true,
), ),
LexiconItemUio.placeholder(),
) )
} }

View file

@ -37,13 +37,13 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.rplexicon.R import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.ui.composable.CategoryHeader
import com.pixelized.rplexicon.ui.composable.FloatingActionButton import com.pixelized.rplexicon.ui.composable.FloatingActionButton
import com.pixelized.rplexicon.ui.composable.Loader import com.pixelized.rplexicon.ui.composable.Loader
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
import com.pixelized.rplexicon.ui.navigation.screens.navigateToLexiconDetail import com.pixelized.rplexicon.ui.navigation.screens.navigateToLexiconDetail
import com.pixelized.rplexicon.ui.navigation.screens.navigateToLexiconSearch import com.pixelized.rplexicon.ui.navigation.screens.navigateToLexiconSearch
import com.pixelized.rplexicon.ui.screens.quest.list.QuestCategory
import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.ui.theme.LexiconTheme
import com.pixelized.rplexicon.utilitary.extentions.cell import com.pixelized.rplexicon.utilitary.extentions.cell
import com.pixelized.rplexicon.utilitary.extentions.lexicon import com.pixelized.rplexicon.utilitary.extentions.lexicon
@ -56,9 +56,8 @@ fun LexiconScreen(
viewModel: LexiconViewModel = hiltViewModel(), viewModel: LexiconViewModel = hiltViewModel(),
lazyListState: LazyListState, lazyListState: LazyListState,
) { ) {
val scope = rememberCoroutineScope()
val screen = LocalScreenNavHost.current val screen = LocalScreenNavHost.current
val scope = rememberCoroutineScope()
val refresh = rememberPullRefreshState( val refresh = rememberPullRefreshState(
refreshing = false, refreshing = false,
onRefresh = { onRefresh = {
@ -67,7 +66,6 @@ fun LexiconScreen(
} }
}, },
) )
val isFabExpended = remember { val isFabExpended = remember {
derivedStateOf { derivedStateOf {
lazyListState.canScrollForward.not() && viewModel.items.value.isNotEmpty() lazyListState.canScrollForward.not() && viewModel.items.value.isNotEmpty()
@ -126,7 +124,7 @@ private fun LexiconScreenContent(
items(count = 16) { items(count = 16) {
LexiconItem( LexiconItem(
modifier = Modifier.cell(), modifier = Modifier.cell(),
item = LexiconItemUio.preview(placeholder = true), item = LexiconItemUio.placeholder(),
) )
} }
} }
@ -143,11 +141,11 @@ private fun LexiconScreenContent(
item( item(
contentType = { "Header" }, contentType = { "Header" },
) { ) {
LexiconCategory( CategoryHeader(
modifier = Modifier modifier = Modifier
.padding(top = if (index == 0) 0.dp else 16.dp) .padding(top = if (index == 0) 0.dp else 16.dp)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
item = it, text = it,
) )
} }
} }
@ -218,24 +216,7 @@ private fun LexiconScreenContentPreview() {
), ),
refreshing = remember { mutableStateOf(false) }, refreshing = remember { mutableStateOf(false) },
isFabExpended = remember { mutableStateOf(true) }, isFabExpended = remember { mutableStateOf(true) },
items = remember { items = rememberLexiconGroupStatePreview(),
mutableStateOf(
listOf(
LexiconGroupUio(
category = null,
items = listOf(
LexiconItemUio(
id = "Brulkhai-1",
name = "Brulkhai",
diminutive = "Bru",
gender = "Female",
race = "Half-orc",
)
),
),
)
)
},
onSearch = { }, onSearch = { },
onItem = { }, onItem = { },
) )

View file

@ -52,10 +52,8 @@ class LexiconViewModel @Inject constructor(
.sortedBy { it.name } .sortedBy { it.name }
.groupBy( .groupBy(
keySelector = { keySelector = {
LexiconCategoryUio( it.category
title = it.category
?: context.getString(R.string.default_category_other) ?: context.getString(R.string.default_category_other)
)
}, },
valueTransform = { item -> valueTransform = { item ->
LexiconItemUio( LexiconItemUio(
@ -74,7 +72,7 @@ class LexiconViewModel @Inject constructor(
items = item.value, items = item.value,
) )
} }
.sortedBy { orderRepository.findLexiconOrder(quest = it.category?.title) } .sortedBy { orderRepository.findLexiconOrder(quest = it.category) }
} }
} }
launch { launch {

View file

@ -0,0 +1,82 @@
package com.pixelized.rplexicon.ui.screens.lexicon.list
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
@Composable
@Stable
fun rememberLexiconGroupStatePreview(): State<List<LexiconGroupUio>> {
return remember {
mutableStateOf(
listOf(
LexiconGroupUio(
category = "Personnage joueur",
items = listOf(
LexiconItemUio(
id = "Brulkhai-1",
name = "Brulkhai",
diminutive = "Bru",
gender = "Femme",
race = "Demi-orc",
),
LexiconItemUio(
id = "Léandre-1",
name = "Léandre",
diminutive = null,
gender = "Homme",
race = "Humain",
),
LexiconItemUio(
id = "Nelia-1",
name = "Nelia",
diminutive = "Nel",
gender = "Femme",
race = "Elfe",
),
LexiconItemUio(
id = "Tigrane-1",
name = "Tigrane",
diminutive = null,
gender = "Homme",
race = "Tieffelin",
),
LexiconItemUio(
id = "Unathana-1",
name = "Unathana",
diminutive = "Una",
gender = "Femme",
race = "Demi-elfe",
),
),
),
LexiconGroupUio(
category = "Argynvosthold",
items = listOf(
LexiconItemUio(
id = "Godfrey Gwylin-1",
name = "Godfrey Gwylin",
diminutive = null,
gender = "Homme",
race = "Inconnu",
),
),
),
LexiconGroupUio(
category = "Vallakiens",
items = listOf(
LexiconItemUio(
id = "Godfrey Gwylin-1",
name = "Godfrey Gwylin",
diminutive = null,
gender = "Homme",
race = "Inconnu",
),
),
),
)
)
}
}

View file

@ -1,26 +0,0 @@
package com.pixelized.rplexicon.ui.screens.location.list
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
@Stable
data class LocationCategoryUio(
val title: String,
)
@Composable
fun LocationCategory(
modifier: Modifier = Modifier,
item: LocationCategoryUio,
) {
Text(
modifier = modifier,
style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Light,
text = item.title,
)
}

View file

@ -1,9 +0,0 @@
package com.pixelized.rplexicon.ui.screens.location.list
import androidx.compose.runtime.Stable
@Stable
data class LocationGroupUio(
val category: LocationCategoryUio?,
val maps: List<LocationItemUio>,
)

View file

@ -26,6 +26,12 @@ import com.pixelized.rplexicon.utilitary.extentions.cell
import com.pixelized.rplexicon.utilitary.extentions.lexicon import com.pixelized.rplexicon.utilitary.extentions.lexicon
import com.pixelized.rplexicon.utilitary.extentions.placeholder import com.pixelized.rplexicon.utilitary.extentions.placeholder
@Stable
data class LocationGroupUio(
val category: String?,
val maps: List<LocationItemUio>,
)
@Stable @Stable
data class LocationItemUio( data class LocationItemUio(
val id: String, val id: String,

View file

@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.rplexicon.ui.composable.CategoryHeader
import com.pixelized.rplexicon.ui.composable.Loader import com.pixelized.rplexicon.ui.composable.Loader
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
@ -118,11 +119,11 @@ private fun LocationContent(
item( item(
contentType = { "Header" }, contentType = { "Header" },
) { ) {
LocationCategory( CategoryHeader(
modifier = Modifier modifier = Modifier
.padding(top = if (index == 0) 0.dp else 16.dp) .padding(top = if (index == 0) 0.dp else 16.dp)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
item = it, text = it,
) )
} }
} }

View file

@ -50,10 +50,8 @@ class LocationViewModel @Inject constructor(
.sortedBy { it.name } .sortedBy { it.name }
.groupBy( .groupBy(
keySelector = { entry -> keySelector = { entry ->
LocationCategoryUio( entry.category
title = entry.category
?: context.getString(R.string.default_category_other) ?: context.getString(R.string.default_category_other)
)
}, },
valueTransform = { entry -> valueTransform = { entry ->
LocationItemUio( LocationItemUio(
@ -69,7 +67,7 @@ class LocationViewModel @Inject constructor(
) )
} }
.sortedBy { item -> .sortedBy { item ->
item.category?.title?.let { item.category?.let {
orderRepository.findMapOrder(quest = it) orderRepository.findMapOrder(quest = it)
} }
} }

View file

@ -1,26 +0,0 @@
package com.pixelized.rplexicon.ui.screens.quest.list
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
@Stable
data class QuestCategoryUio(
val title: String,
)
@Composable
fun QuestCategory(
modifier: Modifier = Modifier,
item: QuestCategoryUio,
) {
Text(
modifier = modifier,
style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Light,
text = item.title,
)
}

View file

@ -1,11 +0,0 @@
package com.pixelized.rplexicon.ui.screens.quest.list
import androidx.compose.runtime.Stable
@Stable
data class QuestGroupUio(
val category: QuestCategoryUio,
val quests: List<QuestItemUio>,
) {
val complete = quests.all { it.complete }
}

View file

@ -26,6 +26,14 @@ import com.pixelized.rplexicon.utilitary.extentions.cell
import com.pixelized.rplexicon.utilitary.extentions.lexicon import com.pixelized.rplexicon.utilitary.extentions.lexicon
import com.pixelized.rplexicon.utilitary.extentions.placeholder import com.pixelized.rplexicon.utilitary.extentions.placeholder
@Stable
data class QuestGroupUio(
val category: String,
val quests: List<QuestItemUio>,
) {
val complete = quests.all { it.complete }
}
@Stable @Stable
data class QuestItemUio( data class QuestItemUio(
val id: String, val id: String,

View file

@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.rplexicon.ui.composable.CategoryHeader
import com.pixelized.rplexicon.ui.composable.Loader import com.pixelized.rplexicon.ui.composable.Loader
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
@ -117,11 +118,11 @@ private fun QuestListContent(
item( item(
contentType = { "Header" }, contentType = { "Header" },
) { ) {
QuestCategory( CategoryHeader(
modifier = Modifier modifier = Modifier
.padding(top = if (index == 0) 0.dp else 16.dp) .padding(top = if (index == 0) 0.dp else 16.dp)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
item = entry.category, text = entry.category,
) )
} }
items( items(
@ -167,9 +168,7 @@ private fun QuestListPreview() {
mutableStateOf( mutableStateOf(
listOf( listOf(
QuestGroupUio( QuestGroupUio(
category = QuestCategoryUio( category = "Faerûn",
title = "Faerûn",
),
quests = listOf( quests = listOf(
QuestItemUio.preview( QuestItemUio.preview(
id = "La chasse aux loups", id = "La chasse aux loups",

View file

@ -51,10 +51,8 @@ class QuestListViewModel @Inject constructor(
.sortedBy { it.complete } .sortedBy { it.complete }
.groupBy( .groupBy(
keySelector = { keySelector = {
QuestCategoryUio( it.category
title = it.category ?: context.getString(R.string.default_category_other)
?: context.getString(R.string.default_category_other),
)
}, },
valueTransform = { item -> valueTransform = { item ->
QuestItemUio( QuestItemUio(
@ -65,7 +63,7 @@ class QuestListViewModel @Inject constructor(
}, },
) )
.map { QuestGroupUio(category = it.key, quests = it.value) } .map { QuestGroupUio(category = it.key, quests = it.value) }
.sortedBy { order.findQuestOrder(quest = it.category.title) } .sortedBy { order.findQuestOrder(quest = it.category) }
.sortedBy { it.complete } .sortedBy { it.complete }
.toList() .toList()