Refactor TopAppBar into Toolbar to avoid weird Behavior.
This commit is contained in:
parent
f43af80f7c
commit
039f124f88
14 changed files with 341 additions and 111 deletions
|
|
@ -0,0 +1,43 @@
|
|||
package com.pixelized.rplexicon.ui.composable
|
||||
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarColors
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Toolbar(
|
||||
modifier: Modifier = Modifier,
|
||||
title: @Composable () -> Unit,
|
||||
navigationIcon: @Composable () -> Unit = {},
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
|
||||
backgroundColor: Color = MaterialTheme.colorScheme.surface,
|
||||
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = Color.Transparent,
|
||||
),
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
color = backgroundColor,
|
||||
) {
|
||||
TopAppBar(
|
||||
title = title,
|
||||
navigationIcon = navigationIcon,
|
||||
actions = actions,
|
||||
windowInsets = windowInsets,
|
||||
colors = colors,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,6 @@ import androidx.compose.material3.IconButton
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
|
@ -39,6 +38,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.Loader
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToAdventureChapters
|
||||
|
|
@ -100,7 +100,7 @@ private fun AdventureListContent(
|
|||
modifier = modifier,
|
||||
topBar = {
|
||||
val shadow = rememberAnimatedShadow(gridState)
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = shadow.value),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
|
|||
|
|
@ -22,12 +22,10 @@ import androidx.compose.material3.IconButton
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
|
|
@ -37,11 +35,11 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.Loader
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToAdventureDetail
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
|
|
@ -94,7 +92,7 @@ private fun AdventureChapterContent(
|
|||
modifier = modifier,
|
||||
topBar = {
|
||||
val shadow = rememberAnimatedShadow(lazyListState)
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = shadow.value),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ import androidx.compose.material3.IconButton
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableFloatState
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
|
|
@ -38,6 +38,7 @@ import androidx.compose.runtime.saveable.mapSaver
|
|||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
|
|
@ -50,10 +51,12 @@ import androidx.compose.ui.platform.LocalDensity
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||
import com.pixelized.rplexicon.ui.composable.images.rememberBackgroundGradient
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
|
|
@ -96,6 +99,14 @@ private data class TitleLayoutInfo(
|
|||
val height: Float,
|
||||
)
|
||||
|
||||
@Stable
|
||||
private data class AnimatedValues(
|
||||
val topAppBarAlpha: State<Float>,
|
||||
val topAppBarColor: State<Color>,
|
||||
val topBarElevation: State<Dp>,
|
||||
val backgroundAlpha: State<Float>,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun AdventureDetailContent(
|
||||
|
|
@ -115,7 +126,9 @@ private fun AdventureDetailContent(
|
|||
onBack: () -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
) {
|
||||
val nestedScrollOffset = rememberSaveable { mutableFloatStateOf(0f) }
|
||||
val nestedScrollOffset = rememberSaveable {
|
||||
mutableFloatStateOf(0f)
|
||||
}
|
||||
val titleLayoutInfo = rememberSaveable(stateSaver = TitleLayoutInfoSaver) {
|
||||
mutableStateOf(null)
|
||||
}
|
||||
|
|
@ -131,25 +144,10 @@ private fun AdventureDetailContent(
|
|||
}
|
||||
}
|
||||
}
|
||||
val topAppBarAlpha = remember {
|
||||
derivedStateOf {
|
||||
titleLayoutInfo.value?.let { info ->
|
||||
when {
|
||||
-nestedScrollOffset.floatValue < info.position -> 0f
|
||||
-nestedScrollOffset.floatValue > info.position + info.height -> 1f
|
||||
info.height != 0f -> (-nestedScrollOffset.floatValue - info.position) / info.height
|
||||
else -> 0f
|
||||
}.coerceIn(minimumValue = 0f, maximumValue = 1f)
|
||||
} ?: 0f
|
||||
}
|
||||
}
|
||||
val backgroundAlpha = remember {
|
||||
derivedStateOf {
|
||||
titleLayoutInfo.value?.let { info ->
|
||||
(info.position + nestedScrollOffset.floatValue) / info.position
|
||||
} ?: 0f
|
||||
}
|
||||
}
|
||||
val animatedValues = rememberAnimatedValues(
|
||||
nestedScrollOffset = nestedScrollOffset,
|
||||
titleLayoutInfo = titleLayoutInfo,
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = modifier,
|
||||
|
|
@ -159,7 +157,7 @@ private fun AdventureDetailContent(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(ratio = 1f)
|
||||
.alpha(alpha = backgroundAlpha.value)
|
||||
.alpha(alpha = animatedValues.backgroundAlpha.value)
|
||||
.offset { IntOffset(x = 0, y = nestedScrollOffset.floatValue.toInt() / 2) },
|
||||
colorFilter = null,
|
||||
background = rememberBackgroundGradient(0f, 0f, 0.1f, 0.7f, 1f),
|
||||
|
|
@ -170,10 +168,9 @@ private fun AdventureDetailContent(
|
|||
Column(
|
||||
modifier = Modifier.nestedScroll(connection = nestedScrollConnexion)
|
||||
) {
|
||||
TopAppBar(
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = Color.Transparent,
|
||||
),
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = animatedValues.topBarElevation.value),
|
||||
backgroundColor = animatedValues.topAppBarColor.value,
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(
|
||||
|
|
@ -184,7 +181,7 @@ private fun AdventureDetailContent(
|
|||
},
|
||||
title = {
|
||||
val alpha = animateFloatAsState(
|
||||
targetValue = topAppBarAlpha.value,
|
||||
targetValue = animatedValues.topAppBarAlpha.value,
|
||||
label = "TopAppBarLabel",
|
||||
)
|
||||
Text(
|
||||
|
|
@ -242,6 +239,63 @@ private fun AdventureDetailContent(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberAnimatedValues(
|
||||
nestedScrollOffset: MutableFloatState,
|
||||
titleLayoutInfo: MutableState<TitleLayoutInfo?>,
|
||||
): AnimatedValues {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
|
||||
val topAppBarAlpha = remember(titleLayoutInfo, nestedScrollOffset) {
|
||||
derivedStateOf {
|
||||
titleLayoutInfo.value?.let { info ->
|
||||
when {
|
||||
-nestedScrollOffset.floatValue < info.position -> 0f
|
||||
-nestedScrollOffset.floatValue > info.position + info.height -> 1f
|
||||
info.height != 0f -> (-nestedScrollOffset.floatValue - info.position) / info.height
|
||||
else -> 0f
|
||||
}.coerceIn(minimumValue = 0f, maximumValue = 1f)
|
||||
} ?: 0f
|
||||
}
|
||||
}
|
||||
val backgroundAlpha = remember(titleLayoutInfo, nestedScrollOffset) {
|
||||
derivedStateOf {
|
||||
titleLayoutInfo.value?.let { info ->
|
||||
(info.position + nestedScrollOffset.floatValue) / info.position
|
||||
}?.coerceIn(minimumValue = 0f, maximumValue = 1f) ?: 0f
|
||||
}
|
||||
}
|
||||
val topAppBarColor = remember(backgroundAlpha, colorScheme) {
|
||||
derivedStateOf {
|
||||
when (backgroundAlpha.value) {
|
||||
0f -> colorScheme.surface
|
||||
else -> Color.Transparent
|
||||
}
|
||||
}
|
||||
}
|
||||
val topBarElevation = remember(backgroundAlpha) {
|
||||
derivedStateOf {
|
||||
when (backgroundAlpha.value) {
|
||||
0f -> 4.dp
|
||||
else -> 0.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
return remember(
|
||||
topAppBarAlpha,
|
||||
backgroundAlpha,
|
||||
topAppBarColor,
|
||||
topBarElevation,
|
||||
) {
|
||||
AnimatedValues(
|
||||
topAppBarAlpha = topAppBarAlpha,
|
||||
backgroundAlpha = backgroundAlpha,
|
||||
topAppBarColor = topAppBarColor,
|
||||
topBarElevation = topBarElevation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val TitleLayoutInfoSaver: Saver<TitleLayoutInfo?, Any> = run {
|
||||
val positionKey = "position"
|
||||
val heightKey = "height"
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import androidx.compose.material3.ScrollableTabRow
|
|||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
|
|
@ -60,6 +59,7 @@ import com.pixelized.rplexicon.NO_WINDOW_INSETS
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.KeepOnScreen
|
||||
import com.pixelized.rplexicon.ui.composable.Loader
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.edit.HandleHitPointEditDialog
|
||||
import com.pixelized.rplexicon.ui.composable.edit.HandleSkillEditDialog
|
||||
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
|
||||
|
|
@ -279,7 +279,7 @@ private fun CharacterSheetContent(
|
|||
containerColor = Color.Transparent,
|
||||
contentWindowInsets = NO_WINDOW_INSETS,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ package com.pixelized.rplexicon.ui.screens.lexicon.detail
|
|||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
|
|
@ -16,6 +18,9 @@ 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.heightIn
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
|
|
@ -26,20 +31,24 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
|
@ -47,20 +56,22 @@ import androidx.compose.ui.text.font.FontStyle
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.images.AsyncImage
|
||||
import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||
import com.pixelized.rplexicon.ui.composable.images.FullScreenImageHandler
|
||||
import com.pixelized.rplexicon.ui.composable.images.FullScreenImageViewModel
|
||||
import com.pixelized.rplexicon.ui.composable.images.rememberBackgroundGradient
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToCharacterSheet
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.annotate
|
||||
import com.pixelized.rplexicon.utilitary.dropCapRegex
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.scrollOffset
|
||||
import com.pixelized.rplexicon.utilitary.extentions.string.searchCriterion
|
||||
import com.pixelized.rplexicon.utilitary.highlightRegex
|
||||
import com.pixelized.rplexicon.utilitary.styleWith
|
||||
|
|
@ -79,6 +90,14 @@ data class LexiconDetailUio(
|
|||
val tags: String?,
|
||||
)
|
||||
|
||||
@Stable
|
||||
private data class AnimatedValues(
|
||||
val topAppBarAlpha: State<Float>,
|
||||
val topAppBarColor: State<Color>,
|
||||
val topBarElevation: State<Dp>,
|
||||
val backgroundAlpha: State<Float>,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun LexiconDetailScreen(
|
||||
viewModel: LexiconDetailViewModel = hiltViewModel(),
|
||||
|
|
@ -90,7 +109,9 @@ fun LexiconDetailScreen(
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
LexiconDetailContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding(),
|
||||
lexicon = viewModel.character,
|
||||
highlight = viewModel.highlight,
|
||||
haveCharacterSheet = viewModel.haveCharacterSheet,
|
||||
|
|
@ -120,63 +141,42 @@ private fun LexiconDetailContent(
|
|||
val typography = MaterialTheme.lexicon.typography
|
||||
val highlightRegex = remember(highlight) { highlightRegex(terms = highlight.searchCriterion()) }
|
||||
val dropCapRegex = remember { dropCapRegex() }
|
||||
val paddingTop =
|
||||
with(LocalDensity.current) { LocalConfiguration.current.screenWidthDp.toDp() } + 56.dp
|
||||
val animatedValues = rememberAnimatedValues(
|
||||
scrollState = state,
|
||||
delta = paddingTop,
|
||||
)
|
||||
|
||||
val item = lexicon.value
|
||||
val backgroundUri = remember(item) {
|
||||
item?.portrait?.firstOrNull()
|
||||
val background = remember(item) {
|
||||
mutableStateOf(
|
||||
item?.portrait?.firstOrNull()
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
Box(
|
||||
modifier = modifier,
|
||||
containerColor = Color.Transparent,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
modifier = Modifier.shadow(elevation = 4.dp),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_arrow_back_ios_new_24),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
AnimatedVisibility(visible = haveCharacterSheet.value) {
|
||||
IconButton(onClick = { item?.name?.let(onCharacterSheet) }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_d20_24),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(id = R.string.lexicon_detail__title))
|
||||
},
|
||||
) {
|
||||
BackgroundPortrait(
|
||||
background = background,
|
||||
animatedValues = animatedValues,
|
||||
state = state,
|
||||
)
|
||||
Column {
|
||||
AnimatedToolBar(
|
||||
animatedValues = animatedValues,
|
||||
onBack = onBack,
|
||||
haveCharacterSheet = haveCharacterSheet,
|
||||
item = item,
|
||||
onCharacterSheet = onCharacterSheet
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
Surface(
|
||||
modifier = Modifier.padding(paddingValues = paddingValues),
|
||||
) {
|
||||
backgroundUri?.let { uri ->
|
||||
BackgroundImage(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(ratio = 1f)
|
||||
.scrollOffset(scrollState = state) { -it / 2 },
|
||||
model = uri,
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(state)
|
||||
.padding(
|
||||
top = when (backgroundUri) {
|
||||
null -> 16.dp
|
||||
else -> MaterialTheme.lexicon.dimens.detailPadding
|
||||
},
|
||||
bottom = 16.dp,
|
||||
.verticalScroll(state = state)
|
||||
.backgroundPadding(
|
||||
background = background,
|
||||
padding = paddingTop,
|
||||
),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
|
|
@ -360,6 +360,85 @@ private fun LexiconDetailContent(
|
|||
}
|
||||
}
|
||||
|
||||
private fun Modifier.backgroundPadding(
|
||||
background: MutableState<Any?>,
|
||||
padding: Dp,
|
||||
): Modifier {
|
||||
return this.padding(
|
||||
top = when (background.value) {
|
||||
null -> 16.dp
|
||||
else -> padding
|
||||
},
|
||||
bottom = 16.dp,
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun AnimatedToolBar(
|
||||
modifier: Modifier = Modifier,
|
||||
animatedValues: AnimatedValues,
|
||||
onBack: () -> Unit,
|
||||
haveCharacterSheet: State<Boolean>,
|
||||
item: LexiconDetailUio?,
|
||||
onCharacterSheet: (String) -> Unit
|
||||
) {
|
||||
Toolbar(
|
||||
modifier = modifier.shadow(elevation = animatedValues.topBarElevation.value),
|
||||
backgroundColor = animatedValues.topAppBarColor.value,
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_arrow_back_ios_new_24),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
AnimatedVisibility(visible = haveCharacterSheet.value) {
|
||||
IconButton(onClick = { item?.name?.let(onCharacterSheet) }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_d20_24),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
title = {
|
||||
val alpha = animateFloatAsState(
|
||||
targetValue = animatedValues.topAppBarAlpha.value,
|
||||
label = "TopAppBarLabel",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alpha(alpha = alpha.value),
|
||||
text = stringResource(id = R.string.lexicon_detail__title),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BackgroundPortrait(
|
||||
modifier: Modifier = Modifier,
|
||||
background: MutableState<Any?>,
|
||||
animatedValues: AnimatedValues,
|
||||
state: ScrollState
|
||||
) {
|
||||
background.value?.let { uri ->
|
||||
BackgroundImage(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(ratio = 1f)
|
||||
.alpha(alpha = animatedValues.backgroundAlpha.value)
|
||||
.offset { IntOffset(x = 0, y = -state.value / 2) }
|
||||
.then(other = modifier),
|
||||
colorFilter = null,
|
||||
background = rememberBackgroundGradient(0f, 0f, 0.1f, 0.7f, 1f),
|
||||
model = uri,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberPortraitWidth(): Dp {
|
||||
val configuration = LocalConfiguration.current
|
||||
|
|
@ -373,6 +452,64 @@ private fun rememberPortraitWidth(): Dp {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberAnimatedValues(
|
||||
scrollState: ScrollState,
|
||||
delta: Dp,
|
||||
): AnimatedValues {
|
||||
val density = LocalDensity.current
|
||||
val deltaPx by remember {
|
||||
derivedStateOf {
|
||||
with(density) { delta.toPx() }
|
||||
}
|
||||
}
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
|
||||
val backgroundAlpha = remember(scrollState, delta) {
|
||||
derivedStateOf {
|
||||
((deltaPx - scrollState.value.toFloat()) / deltaPx)
|
||||
.coerceIn(minimumValue = 0f, maximumValue = 1f)
|
||||
}
|
||||
}
|
||||
val topAppBarAlpha = remember(scrollState, delta) {
|
||||
derivedStateOf {
|
||||
when (backgroundAlpha.value) {
|
||||
0f -> 1f
|
||||
else -> 0f
|
||||
}
|
||||
}
|
||||
}
|
||||
val topAppBarColor = remember(backgroundAlpha, colorScheme) {
|
||||
derivedStateOf {
|
||||
when (backgroundAlpha.value) {
|
||||
0f -> colorScheme.surface
|
||||
else -> Color.Transparent
|
||||
}
|
||||
}
|
||||
}
|
||||
val topBarElevation = remember(backgroundAlpha) {
|
||||
derivedStateOf {
|
||||
when (backgroundAlpha.value) {
|
||||
0f -> 4.dp
|
||||
else -> 0.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
return remember(
|
||||
topAppBarAlpha,
|
||||
backgroundAlpha,
|
||||
topAppBarColor,
|
||||
topBarElevation,
|
||||
) {
|
||||
AnimatedValues(
|
||||
topAppBarAlpha = topAppBarAlpha,
|
||||
backgroundAlpha = backgroundAlpha,
|
||||
topAppBarColor = topAppBarColor,
|
||||
topBarElevation = topBarElevation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO, heightDp = 980)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES, heightDp = 980)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
|
|
@ -45,6 +44,7 @@ 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.Loader
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
|
||||
import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
|
|
@ -130,7 +130,7 @@ private fun LexiconScreenContent(
|
|||
containerColor = Color.Transparent,
|
||||
topBar = {
|
||||
val shadow = rememberAnimatedShadow(lazyListState)
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = shadow.value),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.pixelized.rplexicon.ui.screens.location.detail
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
|
|
@ -39,7 +38,6 @@ import androidx.compose.material3.SnackbarDuration
|
|||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.minimumInteractiveComponentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
|
@ -76,6 +74,7 @@ import androidx.compose.ui.unit.min
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.LocalSnack
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.images.AsyncImage
|
||||
import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||
import com.pixelized.rplexicon.ui.composable.images.FullScreenImageHandler
|
||||
|
|
@ -259,7 +258,7 @@ private fun LocationContent(
|
|||
Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = 4.dp),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
|
|
@ -43,6 +42,7 @@ 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.Loader
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
|
||||
import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
|
|
@ -121,7 +121,7 @@ private fun LocationContent(
|
|||
containerColor = Color.Transparent,
|
||||
topBar = {
|
||||
val shadow = rememberAnimatedShadow(lazyListState)
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = shadow.value),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
|
|
@ -53,6 +52,7 @@ 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.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.images.AsyncImage
|
||||
import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||
import com.pixelized.rplexicon.ui.composable.images.FullScreenImageHandler
|
||||
|
|
@ -139,7 +139,7 @@ private fun QuestDetailContent(
|
|||
modifier = modifier,
|
||||
containerColor = Color.Transparent,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = 4.dp),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import androidx.compose.material3.Surface
|
|||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.SwitchDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
|
|
@ -46,6 +45,7 @@ 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.Loader
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
|
||||
import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
|
|
@ -134,7 +134,7 @@ private fun QuestListContent(
|
|||
containerColor = Color.Transparent,
|
||||
topBar = {
|
||||
val shadow = rememberAnimatedShadow(lazyListState)
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = shadow.value),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberDrawerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
|
|
@ -74,9 +72,11 @@ import com.pixelized.rplexicon.LocalRollOverlay
|
|||
import com.pixelized.rplexicon.NO_WINDOW_INSETS
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.isInDarkTheme
|
||||
import com.pixelized.rplexicon.ui.composable.BlurredOverlayHostState
|
||||
import com.pixelized.rplexicon.ui.composable.CategoryHeader
|
||||
import com.pixelized.rplexicon.ui.composable.ModalNavigationDrawer
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItem
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDetailDialog
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationGroupUio
|
||||
|
|
@ -85,7 +85,6 @@ import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
|||
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCard
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.preview.rememberRollAlterations
|
||||
import com.pixelized.rplexicon.isInDarkTheme
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -259,8 +258,8 @@ private fun RollOverlayContent(
|
|||
containerColor = Color.Transparent,
|
||||
contentWindowInsets = NO_WINDOW_INSETS,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
|
||||
Toolbar(
|
||||
backgroundColor = Color.Transparent,
|
||||
title = { },
|
||||
actions = {
|
||||
IconButton(onClick = onClose) {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import androidx.compose.material3.IconButton
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -29,6 +28,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ThemeViewModel
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.navigation.rootOption
|
||||
|
|
@ -88,7 +88,7 @@ private fun SettingsContent(
|
|||
modifier = modifier,
|
||||
topBar = {
|
||||
val shadow = rememberAnimatedShadow(scrollState = scrollState)
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = shadow.value),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
@ -105,7 +105,7 @@ private fun SettingsContent(
|
|||
},
|
||||
content = { paddings ->
|
||||
Surface(
|
||||
modifier = Modifier.verticalScroll(state = scrollState)
|
||||
modifier = Modifier.verticalScroll(state = scrollState),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(paddingValues = paddings),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
|
|
@ -43,8 +42,9 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||
import com.pixelized.rplexicon.ui.composable.Toolbar
|
||||
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
|
||||
import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.annotate
|
||||
|
|
@ -109,7 +109,7 @@ private fun SpellDetailContent(
|
|||
modifier = modifier,
|
||||
containerColor = Color.Transparent,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
Toolbar(
|
||||
modifier = Modifier.shadow(elevation = 4.dp),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue