diff --git a/app/src/main/java/com/pixelized/rplexicon/model/QuestEntry.kt b/app/src/main/java/com/pixelized/rplexicon/model/QuestEntry.kt index 3ab9693..767e0a5 100644 --- a/app/src/main/java/com/pixelized/rplexicon/model/QuestEntry.kt +++ b/app/src/main/java/com/pixelized/rplexicon/model/QuestEntry.kt @@ -1,11 +1,13 @@ package com.pixelized.rplexicon.model +import android.net.Uri import androidx.compose.runtime.Stable @Stable data class Quest( val id: Int, val title: String, + val background: Uri?, val entries: List, ) @@ -20,4 +22,5 @@ data class QuestEntry( val groupReward: String?, val individualReward: String?, val description: String, + val background: Uri?, ) \ No newline at end of file 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 b4e7c0c..4e0592f 100644 --- a/app/src/main/java/com/pixelized/rplexicon/repository/LexiconRepository.kt +++ b/app/src/main/java/com/pixelized/rplexicon/repository/LexiconRepository.kt @@ -13,6 +13,7 @@ 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 @@ -135,12 +136,6 @@ class LexiconRepository @Inject constructor( } } - private fun String?.toUriOrNull(): Uri? = try { - this?.takeIf { it.isNotBlank() }?.toUri() - } catch (_: Exception) { - null - } - private val Map?.name: Int get() = this?.getValue(Sheet.NAME) ?: 0 private val Map?.diminutive: Int get() = this?.getValue(Sheet.DIMINUTIVE) ?: 1 private val Map?.gender: Int get() = this?.getValue(Sheet.GENDER) ?: 2 diff --git a/app/src/main/java/com/pixelized/rplexicon/repository/QuestRepository.kt b/app/src/main/java/com/pixelized/rplexicon/repository/QuestRepository.kt index 6abe23a..40652ee 100644 --- a/app/src/main/java/com/pixelized/rplexicon/repository/QuestRepository.kt +++ b/app/src/main/java/com/pixelized/rplexicon/repository/QuestRepository.kt @@ -12,6 +12,7 @@ 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 @@ -82,6 +83,7 @@ class QuestRepository @Inject constructor( Quest( id = index, title = item, + background = questMap[item]?.mapNotNull { it.background }?.randomOrNull(), entries = questMap[item] ?: emptyList(), ) } @@ -96,24 +98,26 @@ class QuestRepository @Inject constructor( ): QuestEntry? { val title = row?.getOrNull(sheetStructure.title) as? String val subtitle = row?.getOrNull(sheetStructure.subtitle) as? String? - val complete = row?.getOrNull(sheetStructure.complete) as? Boolean? ?: false + 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, + 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 @@ -128,6 +132,7 @@ class QuestRepository @Inject constructor( private val Map?.groupReward: Int get() = this?.getValue(Sheet.G_REWARD) ?: 5 private val Map?.individualReward: Int get() = this?.getValue(Sheet.I_REWARD) ?: 6 private val Map?.description: Int get() = this?.getValue(Sheet.DESCRIPTION) ?: 7 + private val Map?.background: Int get() = this?.getValue(Sheet.BACKGROUND) ?: 8 private object Sheet { const val ID = "1sDAay8DjbRYKM39MvEXWs-RuvyxjOFpOfRZLAEWjIUY" @@ -143,6 +148,7 @@ class QuestRepository @Inject constructor( "Récompense de groupe", "Récompense individuelle", "Description", + "fond" ) val TITLE = COLUMNS[0] val SUBTITLE = COLUMNS[1] @@ -152,5 +158,6 @@ class QuestRepository @Inject constructor( val G_REWARD = COLUMNS[5] val I_REWARD = COLUMNS[6] val DESCRIPTION = COLUMNS[7] + val BACKGROUND = COLUMNS[8] } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/composable/BackgroundImage.kt b/app/src/main/java/com/pixelized/rplexicon/ui/composable/BackgroundImage.kt new file mode 100644 index 0000000..e487b49 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/composable/BackgroundImage.kt @@ -0,0 +1,60 @@ +package com.pixelized.rplexicon.ui.composable + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.layout.ContentScale +import com.pixelized.rplexicon.R +import com.skydoves.landscapist.ImageOptions + +@Composable +fun BackgroundImage( + modifier: Modifier = Modifier, + alignment: Alignment = Alignment.TopCenter, + contentScale: ContentScale = ContentScale.Crop, + model: () -> Any?, +) { + Box( + modifier = modifier + ) { + AsyncImage( + modifier = Modifier.matchParentSize(), + imageOptions = ImageOptions( + alignment = alignment, + contentScale = contentScale, + colorFilter = remember { + ColorFilter.colorMatrix( + ColorMatrix().also { it.setToSaturation(0f) } + ) + }, + ), + imageModel = model, + previewPlaceholder = R.drawable.im_brulkhai, + ) + Box( + modifier = Modifier + .matchParentSize() + .background(brush = rememberBackgroundGradient()) + ) + } +} + +@Composable +private fun rememberBackgroundGradient(): Brush { + val colorScheme = MaterialTheme.colorScheme + return remember { + Brush.verticalGradient( + colors = listOf( + colorScheme.surface.copy(alpha = 0.5f), + colorScheme.surface.copy(alpha = 1.0f), + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberCurrentOffset.kt b/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberCurrentOffset.kt new file mode 100644 index 0000000..e1ff94b --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberCurrentOffset.kt @@ -0,0 +1,35 @@ +package com.pixelized.rplexicon.ui.composable.remember + +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember + +/** + * https://stackoverflow.com/questions/73333935/current-scroll-position-value-in-pixels-in-lazycolumn-jetpack-compose + */ +@Composable +fun rememberCurrentOffset(state: LazyListState): State { + val position = remember { derivedStateOf { state.firstVisibleItemIndex } } + val itemOffset = remember { derivedStateOf { state.firstVisibleItemScrollOffset } } + val lastPosition = rememberPrevious(position.value) + val lastItemOffset = rememberPrevious(itemOffset.value) + val currentOffset = remember { mutableStateOf(0) } + + LaunchedEffect(position.value, itemOffset.value) { + if (lastPosition == null || position.value == 0) { + currentOffset.value = itemOffset.value + } else if (lastPosition == position.value) { + currentOffset.value += (itemOffset.value - (lastItemOffset ?: 0)) + } else if (lastPosition > position.value) { + currentOffset.value -= (lastItemOffset ?: 0) + } else { // lastPosition.value < position.value + currentOffset.value += itemOffset.value + } + } + + return currentOffset +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberPrevious.kt b/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberPrevious.kt new file mode 100644 index 0000000..a88778f --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberPrevious.kt @@ -0,0 +1,21 @@ +package com.pixelized.rplexicon.ui.composable.remember + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect + +@Composable +fun rememberPrevious( + current: T, + shouldUpdate: (prev: T?, curr: T) -> Boolean = { a: T?, b: T -> a != b }, +): T? { + val ref = rememberRef() + + // launched after render, so the current render will have the old value anyway + SideEffect { + if (shouldUpdate(ref.value, current)) { + ref.value = current + } + } + + return ref.value +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberRef.kt b/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberRef.kt new file mode 100644 index 0000000..1fad951 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/composable/remember/rememberRef.kt @@ -0,0 +1,23 @@ +package com.pixelized.rplexicon.ui.composable.remember + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.remember + +/** + * Returns a dummy MutableState that does not cause render when setting it + */ +@Composable +fun rememberRef(): MutableState { + // for some reason it always recreated the value with vararg keys, + // leaving out the keys as a parameter for remember for now + return remember { + object : MutableState { + override var value: T? = null + + override fun component1(): T? = value + + override fun component2(): (T?) -> Unit = { value = it } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/detail/LexiconDetailScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/detail/LexiconDetailScreen.kt index 249c803..a196673 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/detail/LexiconDetailScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/detail/LexiconDetailScreen.kt @@ -4,7 +4,6 @@ import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES import android.net.Uri import androidx.compose.foundation.ScrollState -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -35,14 +34,10 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.composed import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.ColorMatrix import androidx.compose.ui.graphics.Shadow import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration @@ -60,6 +55,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import com.pixelized.rplexicon.R import com.pixelized.rplexicon.model.Lexicon import com.pixelized.rplexicon.ui.composable.AsyncImage +import com.pixelized.rplexicon.ui.composable.BackgroundImage import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.utilitary.composable.stringResource @@ -197,32 +193,13 @@ private fun LexiconDetailContent( modifier = Modifier.padding(paddingValues = paddingValues), ) { annotatedItem.portrait.firstOrNull()?.let { uri -> - Box( + BackgroundImage( modifier = Modifier .fillMaxWidth() .aspectRatio(ratio = 1f) .scrollOffset(scrollState = state) { -it / 2 }, - ) { - AsyncImage( - modifier = Modifier.matchParentSize(), - imageOptions = ImageOptions( - alignment = Alignment.TopCenter, - contentScale = ContentScale.Crop, - colorFilter = remember { - ColorFilter.colorMatrix( - ColorMatrix().also { it.setToSaturation(0f) } - ) - }, - ), - imageModel = { uri.toString() }, - previewPlaceholder = R.drawable.im_brulkhai, - ) - Box( - modifier = Modifier - .matchParentSize() - .background(brush = rememberBackgroundGradient()) - ) - } + model = { uri.toString() }, + ) } Column( modifier = Modifier @@ -342,19 +319,6 @@ private fun LexiconDetailContent( } } -@Composable -private fun rememberBackgroundGradient(): Brush { - val colorScheme = MaterialTheme.colorScheme - return remember { - Brush.verticalGradient( - colors = listOf( - colorScheme.surface.copy(alpha = 0.5f), - colorScheme.surface.copy(alpha = 1.0f), - ) - ) - } -} - @Composable private fun rememberPortraitWidth(): Dp { val configuration = LocalConfiguration.current diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/detail/QuestDetailScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/detail/QuestDetailScreen.kt index d755ede..13c6b94 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/detail/QuestDetailScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/detail/QuestDetailScreen.kt @@ -1,17 +1,22 @@ package com.pixelized.rplexicon.ui.screens.quest.detail import android.content.res.Configuration +import android.net.Uri import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -27,10 +32,12 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.composed import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -39,9 +46,12 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.pixelized.rplexicon.R +import com.pixelized.rplexicon.ui.composable.BackgroundImage +import com.pixelized.rplexicon.ui.composable.remember.rememberCurrentOffset import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.utilitary.extentions.lexicon @@ -50,6 +60,7 @@ import java.lang.Integer.min @Stable data class QuestDetailUio( val id: Int, + val background: Uri?, val title: String, val steps: List, ) { @@ -68,6 +79,7 @@ data class QuestDetailUio( @Stable data class AnnotatedQuestDetailUio( val title: String, + val background: Uri?, val steps: List, ) { @Stable @@ -89,6 +101,7 @@ private fun QuestDetailUio.annotate(): AnnotatedQuestDetailUio { return remember { AnnotatedQuestDetailUio( title = title, + background = background, steps = annotatedSteps, ) } @@ -143,6 +156,7 @@ private fun QuestDetailContent( item: State, onBack: () -> Unit, ) { + val state = rememberLazyListState() val annotatedQuest = item.value.annotate() Scaffold( @@ -164,128 +178,158 @@ private fun QuestDetailContent( ) }, content = { padding -> - LazyColumn( + Surface( modifier = Modifier.padding(padding), - contentPadding = PaddingValues( - top = 40.dp, - bottom = 16.dp, - start = 16.dp, - end = 16.dp - ), - verticalArrangement = Arrangement.spacedBy(40.dp), ) { - item { - Column { - Text( - modifier = Modifier.fillMaxWidth(), - textAlign = TextAlign.Center, - style = MaterialTheme.typography.displaySmall, - text = annotatedQuest.title, - ) - Image( - modifier = Modifier - .height(24.dp) - .graphicsLayer { rotationZ = 180f } - .align(Alignment.CenterHorizontally), - painter = painterResource(id = R.drawable.art_divider_1), - contentScale = ContentScale.FillWidth, - alignment = Alignment.Center, - colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface), - contentDescription = null, - ) - } - } - items(annotatedQuest.steps) { quest -> - Column { - quest.subtitle?.let { subtitle -> - Row( + BackgroundImage( + modifier = Modifier + .fillMaxWidth() + .aspectRatio(ratio = 1f) + .scrollOffset(scrollState = state) { -it / 2 }, + model = { annotatedQuest.background }, + ) + LazyColumn( + state = state, + contentPadding = PaddingValues( + top = 248.dp, + bottom = 16.dp, + start = 16.dp, + end = 16.dp + ), + verticalArrangement = Arrangement.spacedBy(0.dp), + ) { + item { + Column { + Text( modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - ) { - Image( - modifier = Modifier.graphicsLayer { rotationY = 180f }, - painter = painterResource(id = R.drawable.art_clip_1), - contentScale = ContentScale.FillWidth, - alignment = Alignment.Center, - colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface), - contentDescription = null, - ) - Text( - modifier = Modifier.padding(all = 8.dp), - textAlign = TextAlign.Center, - style = MaterialTheme.typography.titleLarge, - text = subtitle, - ) - Image( - painter = painterResource(id = R.drawable.art_clip_1), - contentScale = ContentScale.FillWidth, - alignment = Alignment.Center, - colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface), - contentDescription = null, - ) + textAlign = TextAlign.Center, + style = MaterialTheme.typography.displaySmall, + text = annotatedQuest.title, + ) + Image( + modifier = Modifier + .height(24.dp) + .graphicsLayer { rotationZ = 180f } + .align(Alignment.CenterHorizontally), + painter = painterResource(id = R.drawable.art_divider_1), + contentScale = ContentScale.FillWidth, + alignment = Alignment.Center, + colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface), + contentDescription = null, + ) + } + } + items(annotatedQuest.steps) { quest -> + Column( + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + quest.subtitle?.let { subtitle -> + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 64.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + ) { + Image( + modifier = Modifier.graphicsLayer { rotationY = 180f }, + painter = painterResource(id = R.drawable.art_clip_1), + contentScale = ContentScale.FillWidth, + alignment = Alignment.Center, + colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface), + contentDescription = null, + ) + Text( + modifier = Modifier.padding(horizontal = 8.dp), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleLarge, + text = subtitle, + ) + Image( + painter = painterResource(id = R.drawable.art_clip_1), + contentScale = ContentScale.FillWidth, + alignment = Alignment.Center, + colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface), + contentDescription = null, + ) + } } - } - quest.giver?.let { - Text( - modifier = Modifier.padding(top = 8.dp), - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Bold, - text = "Commanditaire", - ) + quest.giver?.let { + Column { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = "Commanditaire", + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = it, + ) + } + } + quest.place?.let { + Column { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = "Lieu", + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = it, + ) + } + } + quest.globalReward?.let { + Column { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = "Récompense de groupe", + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = it, + ) + } + } + quest.individualReward?.let { + Column { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = "Récompense individuelle", + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = it, + ) + } + } + Text( style = MaterialTheme.typography.bodyMedium, - text = it, + text = quest.description, ) } - quest.place?.let { - Text( - modifier = Modifier.padding(top = 8.dp), - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Bold, - text = "Lieu", - ) - Text( - style = MaterialTheme.typography.bodyMedium, - text = it, - ) - } - quest.globalReward?.let { - Text( - modifier = Modifier.padding(top = 8.dp), - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Bold, - text = "Récompense de groupe", - ) - Text( - style = MaterialTheme.typography.bodyMedium, - text = it, - ) - } - quest.individualReward?.let { - Text( - modifier = Modifier.padding(top = 8.dp), - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Bold, - text = "Récompense individuelle", - ) - Text( - style = MaterialTheme.typography.bodyMedium, - text = it, - ) - } - Text( - modifier = Modifier.padding(top = 24.dp), - style = MaterialTheme.typography.bodyMedium, - text = quest.description, - ) } } } + }, ) } +@Stable +private fun Modifier.scrollOffset( + scrollState: LazyListState, + block: (Dp) -> Dp +): Modifier = composed { + val scroll = rememberCurrentOffset(scrollState) + val density = LocalDensity.current + this.offset(y = with(density) { block(scroll.value.toDp()) }) +} + @Composable @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @@ -307,6 +351,7 @@ private class QuestDetailPreviewProvider : PreviewParameterProvider QuestDetailUio.QuestStep( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListScreen.kt index 6f27605..0ac0162 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListScreen.kt @@ -79,7 +79,7 @@ private fun QuestListContent( modifier: Modifier = Modifier, lazyColumnState: LazyListState, paddingValues: PaddingValues = PaddingValues( - top = 6.dp, + top = 8.dp, bottom = 8.dp + 16.dp + 56.dp + 16.dp, ), refreshState: PullRefreshState, diff --git a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/StringEx.kt b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/StringEx.kt index 496996d..6275e1d 100644 --- a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/StringEx.kt +++ b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/StringEx.kt @@ -1,5 +1,8 @@ package com.pixelized.rplexicon.utilitary.extentions +import android.net.Uri +import androidx.core.net.toUri + val String.ARG: String get() = "$this={$this}" val String?.highlightRegex: Regex? @@ -15,3 +18,9 @@ val String?.finderRegex: Regex? ) } +fun String?.toUriOrNull(): Uri? = try { + this?.takeIf { it.isNotBlank() }?.toUri() +} catch (_: Exception) { + null +} +