New Inventory component.
This commit is contained in:
parent
250d9cbb7c
commit
531e4bea98
25 changed files with 842 additions and 77 deletions
|
|
@ -38,7 +38,7 @@ import com.pixelized.rplexicon.ui.screens.rolls.RollOverlay
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.RollOverlayViewModel
|
import com.pixelized.rplexicon.ui.screens.rolls.RollOverlayViewModel
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.rememberBlurredRollOverlayHostState
|
import com.pixelized.rplexicon.ui.screens.rolls.rememberBlurredRollOverlayHostState
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
val NO_WINDOW_INSETS = WindowInsets(0, 0, 0, 0)
|
val NO_WINDOW_INSETS = WindowInsets(0, 0, 0, 0)
|
||||||
|
|
@ -128,7 +128,7 @@ class MainActivity : ComponentActivity() {
|
||||||
Snackbar(
|
Snackbar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
|
@ -35,7 +34,7 @@ import androidx.compose.ui.window.DialogProperties
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.toLabel
|
import com.pixelized.rplexicon.utilitary.extentions.toLabel
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -66,7 +65,7 @@ fun HandleHitPointEditDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.ddBorder(
|
modifier = Modifier.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class SkillEditDialogUio(
|
data class SkillEditDialogUio(
|
||||||
|
|
@ -48,7 +48,7 @@ fun HandleSkillEditDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.ddBorder(
|
modifier = Modifier.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class SpellEditDialogUio(
|
data class SpellEditDialogUio(
|
||||||
|
|
@ -49,7 +49,7 @@ fun HandleSpellEditDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.ddBorder(
|
modifier = Modifier.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
||||||
|
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||||
import android.net.Uri
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
|
@ -27,14 +26,12 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.net.toUri
|
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.data.model.Attack
|
import com.pixelized.rplexicon.data.model.Attack
|
||||||
import com.pixelized.rplexicon.ui.composable.images.AsyncImage
|
import com.pixelized.rplexicon.ui.composable.images.AsyncImage
|
||||||
import com.pixelized.rplexicon.ui.screens.character.composable.common.DiceButton
|
import com.pixelized.rplexicon.ui.screens.character.composable.common.DiceButton
|
||||||
import com.pixelized.rplexicon.ui.screens.character.composable.common.FlatValue
|
import com.pixelized.rplexicon.ui.screens.character.composable.common.FlatValue
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.uri
|
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class AttackUio(
|
data class AttackUio(
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.sizeIn
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.CutCornerShape
|
import androidx.compose.foundation.shape.CutCornerShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Divider
|
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
|
|
@ -26,7 +25,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.toLabel
|
import com.pixelized.rplexicon.utilitary.extentions.toLabel
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -88,7 +87,7 @@ private fun StatPreview() {
|
||||||
Stat(
|
Stat(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(all = 8.dp)
|
.padding(all = 8.dp)
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package com.pixelized.rplexicon.ui.screens.character.composable.dialogs
|
||||||
|
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||||
import android.net.Uri
|
|
||||||
import androidx.compose.foundation.ScrollState
|
import androidx.compose.foundation.ScrollState
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
|
@ -37,7 +36,7 @@ import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.annotateWithDropCap
|
import com.pixelized.rplexicon.utilitary.annotateWithDropCap
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class AlterationDialogDetailUio(
|
data class AlterationDialogDetailUio(
|
||||||
|
|
@ -75,7 +74,7 @@ fun AlterationDetailDialog(
|
||||||
enabled = false,
|
enabled = false,
|
||||||
onClick = { },
|
onClick = { },
|
||||||
)
|
)
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.annotateWithDropCap
|
import com.pixelized.rplexicon.utilitary.annotateWithDropCap
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class SkillDialogDetailUio(
|
data class SkillDialogDetailUio(
|
||||||
|
|
@ -70,7 +70,7 @@ fun SkillDetailDialog(
|
||||||
enabled = false,
|
enabled = false,
|
||||||
onClick = { },
|
onClick = { },
|
||||||
)
|
)
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.pixelized.rplexicon.ui.screens.character.composable.dialogs
|
package com.pixelized.rplexicon.ui.screens.character.composable.dialogs
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.net.Uri
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.ScrollState
|
import androidx.compose.foundation.ScrollState
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
|
@ -40,7 +39,7 @@ import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.annotateWithDropCap
|
import com.pixelized.rplexicon.utilitary.annotateWithDropCap
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class SpellDialogDetailUio(
|
data class SpellDialogDetailUio(
|
||||||
|
|
@ -83,7 +82,7 @@ fun SpellDetailDialog(
|
||||||
enabled = false,
|
enabled = false,
|
||||||
onClick = { },
|
onClick = { },
|
||||||
)
|
)
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
package com.pixelized.rplexicon.ui.screens.character.pages.inventory
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.SizeTransform
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.compose.animation.togetherWith
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
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 com.pixelized.rplexicon.R
|
||||||
|
import com.pixelized.rplexicon.ui.composable.images.AsyncImage
|
||||||
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
data class InventoryItemUio(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val amount: Int,
|
||||||
|
val container: Boolean,
|
||||||
|
val icon: Any?,
|
||||||
|
val items: List<InventoryItemUio> = emptyList(),
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun InventoryItem(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
item: InventoryItemUio,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.then(other = modifier)
|
||||||
|
.aspectRatio(ratio = 1f),
|
||||||
|
) {
|
||||||
|
AsyncImage(
|
||||||
|
modifier = Modifier.matchParentSize(),
|
||||||
|
model = item.icon,
|
||||||
|
contentScale = ContentScale.Fit,
|
||||||
|
)
|
||||||
|
AnimatedContent(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(alignment = Alignment.BottomEnd)
|
||||||
|
.offset(x = 0.dp, y = 4.dp)
|
||||||
|
.padding(horizontal = 2.dp),
|
||||||
|
targetState = item.amount,
|
||||||
|
transitionSpec = {
|
||||||
|
// Compare the incoming number with the previous number.
|
||||||
|
if (targetState > initialState) {
|
||||||
|
// If the target number is larger, it slides up and fades in
|
||||||
|
// while the initial (smaller) number slides up and fades out.
|
||||||
|
slideInVertically { height -> height / 2 } + fadeIn() togetherWith
|
||||||
|
slideOutVertically { height -> -height / 2 } + fadeOut()
|
||||||
|
} else {
|
||||||
|
// If the target number is smaller, it slides down and fades in
|
||||||
|
// while the initial number slides down and fades out.
|
||||||
|
slideInVertically { height -> -height / 2 } + fadeIn() togetherWith
|
||||||
|
slideOutVertically { height -> height / 2 } + fadeOut()
|
||||||
|
}.using(
|
||||||
|
// Disable clipping since the faded slide-in/out should
|
||||||
|
// be displayed out of bounds.
|
||||||
|
SizeTransform(clip = false)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = "Container count size",
|
||||||
|
) { amount ->
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.graphicsLayer { this.alpha = if (amount == 1) 0f else 1f },
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.End,
|
||||||
|
text = amount.takeIf { it > 0 }?.let { "$it" } ?: " ", //
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AnimatedContent(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(alignment = Alignment.TopEnd)
|
||||||
|
.offset(x = 0.dp, y = (-4).dp)
|
||||||
|
.padding(horizontal = 2.dp),
|
||||||
|
targetState = item.items.size,
|
||||||
|
transitionSpec = {
|
||||||
|
// Compare the incoming number with the previous number.
|
||||||
|
if (targetState > initialState) {
|
||||||
|
// If the target number is larger, it slides up and fades in
|
||||||
|
// while the initial (smaller) number slides up and fades out.
|
||||||
|
slideInVertically { height -> height / 2 } + fadeIn() togetherWith
|
||||||
|
slideOutVertically { height -> -height / 2 } + fadeOut()
|
||||||
|
} else {
|
||||||
|
// If the target number is smaller, it slides down and fades in
|
||||||
|
// while the initial number slides down and fades out.
|
||||||
|
slideInVertically { height -> -height / 2 } + fadeIn() togetherWith
|
||||||
|
slideOutVertically { height -> height / 2 } + fadeOut()
|
||||||
|
}.using(
|
||||||
|
// Disable clipping since the faded slide-in/out should
|
||||||
|
// be displayed out of bounds.
|
||||||
|
SizeTransform(clip = false)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = "Container count size",
|
||||||
|
) { amount ->
|
||||||
|
Text(
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.End,
|
||||||
|
text = amount.takeIf { it > 0 }?.let { "$it" } ?: " ", //
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, widthDp = 64)
|
||||||
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, widthDp = 64)
|
||||||
|
private fun InventoryItemPreview(
|
||||||
|
@PreviewParameter(ClassInventoryItemProvider::class) preview: InventoryItemUio,
|
||||||
|
) {
|
||||||
|
LexiconTheme {
|
||||||
|
Surface {
|
||||||
|
InventoryItem(
|
||||||
|
item = preview,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ClassInventoryItemProvider : PreviewParameterProvider<InventoryItemUio> {
|
||||||
|
override val values: Sequence<InventoryItemUio> = sequenceOf(
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 0,
|
||||||
|
name = "Pouch",
|
||||||
|
amount = 1,
|
||||||
|
container = true,
|
||||||
|
icon = R.drawable.icbg_pouch_a_unfaded,
|
||||||
|
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 1,
|
||||||
|
name = "Scroll of blessing",
|
||||||
|
amount = 1,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_scroll_of_bless_unfaded,
|
||||||
|
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 2,
|
||||||
|
name = "Potion of blessing",
|
||||||
|
amount = 2,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_pot_potion_of_healing_unfaded,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,254 @@
|
||||||
|
package com.pixelized.rplexicon.ui.screens.character.pages.inventory
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.animation.animateColor
|
||||||
|
import androidx.compose.animation.core.updateTransition
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||||
|
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.surfaceColorAtElevation
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.compositeOver
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.pixelized.rplexicon.R
|
||||||
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
|
import com.pixelized.rplexicon.utilitary.DraggableItem
|
||||||
|
import com.pixelized.rplexicon.utilitary.dragContainer
|
||||||
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
import com.pixelized.rplexicon.utilitary.rememberGridDragDropState
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
fun Pouet() {
|
||||||
|
val items = remember {
|
||||||
|
mutableStateOf(
|
||||||
|
listOf(
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 0,
|
||||||
|
name = "Pouch",
|
||||||
|
amount = 1,
|
||||||
|
container = true,
|
||||||
|
icon = R.drawable.icbg_pouch_a_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 1,
|
||||||
|
name = "Scroll of blessing",
|
||||||
|
amount = 1,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_scroll_of_bless_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 2,
|
||||||
|
name = "Scroll of spirit weapon",
|
||||||
|
amount = 1,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_book_signedtradebisa_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 3,
|
||||||
|
name = "Potion of healing",
|
||||||
|
amount = 2,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_potion_of_superior_healing_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 4,
|
||||||
|
name = "Potion of supérior healing",
|
||||||
|
amount = 2,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_pot_potion_of_healing_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 5,
|
||||||
|
name = "Potion of holy water",
|
||||||
|
amount = 2,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_grn_holy_water_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 6,
|
||||||
|
name = "Leather armor",
|
||||||
|
amount = 1,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_leather_armour_rogue_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 7,
|
||||||
|
name = "Silver battleaxe",
|
||||||
|
amount = 0,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_battleaxe_plus_one_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 8,
|
||||||
|
name = "Hand crossbow",
|
||||||
|
amount = 0,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_hand_crossbow_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 9,
|
||||||
|
name = "Goodberry",
|
||||||
|
amount = 0,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_food_goodberry_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 10,
|
||||||
|
name = "Goodberry",
|
||||||
|
amount = 0,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_worg_fang_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 11,
|
||||||
|
name = "Lantern of revealing",
|
||||||
|
amount = 0,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_lantern_of_revealing,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 12,
|
||||||
|
name = "Dust of disappearance",
|
||||||
|
amount = 0,
|
||||||
|
container = false,
|
||||||
|
icon = R.drawable.icbg_haste_spore_grenade_unfaded,
|
||||||
|
),
|
||||||
|
InventoryItemUio(
|
||||||
|
id = 13,
|
||||||
|
name = "Pouch",
|
||||||
|
amount = 1,
|
||||||
|
container = true,
|
||||||
|
icon = R.drawable.icbg_pouch_a_unfaded,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val overIndex = remember { mutableIntStateOf(-1) }
|
||||||
|
val contentPadding = remember { PaddingValues(16.dp) }
|
||||||
|
val gridState = rememberLazyGridState()
|
||||||
|
val dragDropState = rememberGridDragDropState(
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
gridState = gridState,
|
||||||
|
onMove = { fromIndex, toIndex ->
|
||||||
|
items.value = items.value.toMutableList().apply {
|
||||||
|
add(toIndex, removeAt(fromIndex))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onOver = { _, toIndex ->
|
||||||
|
val receiver = items.value[toIndex]
|
||||||
|
if (receiver.container) {
|
||||||
|
overIndex.intValue = toIndex
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDrop = { fromIndex, toIndex ->
|
||||||
|
if (fromIndex != toIndex) {
|
||||||
|
val receiver = items.value[toIndex]
|
||||||
|
if (receiver.container) {
|
||||||
|
items.value = items.value.toMutableList().apply {
|
||||||
|
val item = removeAt(fromIndex)
|
||||||
|
val receiverCopy = receiver.copy(
|
||||||
|
items = receiver.items.toMutableList().also {
|
||||||
|
it.add(item)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val receiverIndex = indexOf(receiver)
|
||||||
|
removeAt(receiverIndex)
|
||||||
|
add(receiverIndex, receiverCopy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
LexiconTheme {
|
||||||
|
Surface {
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(5),
|
||||||
|
modifier = Modifier
|
||||||
|
.dragContainer(dragDropState)
|
||||||
|
.fillMaxSize(),
|
||||||
|
state = gridState,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
itemsIndexed(
|
||||||
|
items = items.value,
|
||||||
|
key = { _, item -> item.id },
|
||||||
|
) { index, item ->
|
||||||
|
DraggableItem(
|
||||||
|
dragDropState = dragDropState,
|
||||||
|
index = index
|
||||||
|
) { isDragging, isOvering ->
|
||||||
|
val colorScheme = MaterialTheme.lexicon.colorScheme
|
||||||
|
val transition = updateTransition(
|
||||||
|
targetState = isDragging || isOvering ,
|
||||||
|
label = "Dragging transition",
|
||||||
|
)
|
||||||
|
val backgroundColor = transition.animateColor(
|
||||||
|
label = "Draggable item background color",
|
||||||
|
) {
|
||||||
|
val surface = colorScheme.base.surfaceColorAtElevation(2.dp)
|
||||||
|
when (it) {
|
||||||
|
true -> colorScheme.base.primary.copy(alpha = 0.15f)
|
||||||
|
.compositeOver(surface)
|
||||||
|
|
||||||
|
else -> surface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val outlineColor = transition.animateColor(
|
||||||
|
label = "Draggable item outline color",
|
||||||
|
) {
|
||||||
|
when (it) {
|
||||||
|
true -> colorScheme.base.primary
|
||||||
|
else -> colorScheme.characterSheet.outlineBorder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val innerColor = transition.animateColor(
|
||||||
|
label = "Draggable item inline color",
|
||||||
|
) {
|
||||||
|
when (it) {
|
||||||
|
true -> colorScheme.base.primary
|
||||||
|
else -> colorScheme.characterSheet.innerBorder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.doubleBorder(
|
||||||
|
backgroundColor = backgroundColor.value,
|
||||||
|
outline = remember { RoundedCornerShape(8.dp) },
|
||||||
|
outlineColor = outlineColor.value,
|
||||||
|
inner = remember { RoundedCornerShape(6.dp) },
|
||||||
|
innerColor = innerColor.value,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
InventoryItem(
|
||||||
|
item = item,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio
|
||||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberCharacterSheetStatePreview
|
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberCharacterSheetStatePreview
|
||||||
import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDetailDialog
|
import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDetailDialog
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -146,7 +146,7 @@ fun ProficiencyPageContent(
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.sizeIn(minWidth = 100.dp, minHeight = 116.dp)
|
.sizeIn(minWidth = 100.dp, minHeight = 116.dp)
|
||||||
.ddBorder(outline = outline, inner = inner)
|
.doubleBorder(outline = outline, inner = inner)
|
||||||
.padding(all = 8.dp),
|
.padding(all = 8.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
|
@ -163,7 +163,7 @@ fun ProficiencyPageContent(
|
||||||
}
|
}
|
||||||
sheet.stats.forEach {
|
sheet.stats.forEach {
|
||||||
Stat(
|
Stat(
|
||||||
modifier = Modifier.ddBorder(inner = inner, outline = outline),
|
modifier = Modifier.doubleBorder(inner = inner, outline = outline),
|
||||||
stat = it,
|
stat = it,
|
||||||
onClick = onStats,
|
onClick = onStats,
|
||||||
)
|
)
|
||||||
|
|
@ -266,28 +266,28 @@ private fun ProficiencyLayout(
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.layoutId("SavingThrowsId")
|
.layoutId("SavingThrowsId")
|
||||||
.ddBorder(inner = inner, outline = outline),
|
.doubleBorder(inner = inner, outline = outline),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
content = savingThrows,
|
content = savingThrows,
|
||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.layoutId("ProficienciesId")
|
.layoutId("ProficienciesId")
|
||||||
.ddBorder(inner = inner, outline = outline),
|
.doubleBorder(inner = inner, outline = outline),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
content = proficiencies,
|
content = proficiencies,
|
||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.layoutId("SpeedId")
|
.layoutId("SpeedId")
|
||||||
.ddBorder(inner = inner, outline = outline),
|
.doubleBorder(inner = inner, outline = outline),
|
||||||
content = speed,
|
content = speed,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.layoutId("PassivesId")
|
.layoutId("PassivesId")
|
||||||
.ddBorder(inner = inner, outline = outline),
|
.doubleBorder(inner = inner, outline = outline),
|
||||||
content = passives,
|
content = passives,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.SpaceBetween,
|
verticalArrangement = Arrangement.SpaceBetween,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ import com.pixelized.rplexicon.isInDarkTheme
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.annotatedSpan
|
import com.pixelized.rplexicon.utilitary.extentions.annotatedSpan
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
import com.pixelized.rplexicon.utilitary.highlightRegex
|
import com.pixelized.rplexicon.utilitary.highlightRegex
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
|
|
@ -118,7 +118,7 @@ fun ThrowsCard(
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = inner,
|
inner = inner,
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberAttributesSummary
|
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberAttributesSummary
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class AttributesSummaryUio(
|
data class AttributesSummaryUio(
|
||||||
|
|
@ -45,7 +45,7 @@ fun AttributesSummary(
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberCharacteristicsSummary
|
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberCharacteristicsSummary
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class CharacteristicsSummaryUio(
|
data class CharacteristicsSummaryUio(
|
||||||
|
|
@ -48,7 +48,7 @@ fun CharacteristicsSummary(
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberPassivesSummary
|
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberPassivesSummary
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class PassivesSummaryUio(
|
data class PassivesSummaryUio(
|
||||||
|
|
@ -43,7 +43,7 @@ fun PassivesSummary(
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberProficienciesSummary
|
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberProficienciesSummary
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class ProficiencySummaryUio(
|
data class ProficiencySummaryUio(
|
||||||
|
|
@ -58,7 +58,7 @@ fun ProficiencySummary(
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberSavingThrowsSummary
|
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberSavingThrowsSummary
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class SavingThrowsSummaryUio(
|
data class SavingThrowsSummaryUio(
|
||||||
|
|
@ -46,7 +46,7 @@ fun SavingThrowsSummary(
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberSpellsSummary
|
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberSpellsSummary
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class SpellSummaryUio(
|
data class SpellSummaryUio(
|
||||||
|
|
@ -53,7 +53,7 @@ fun SpellSummary(
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberStatusSummary
|
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberStatusSummary
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.doubleBorder
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.verticalDivider
|
import com.pixelized.rplexicon.utilitary.extentions.modifier.verticalDivider
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -80,7 +80,7 @@ fun StatusSummary(
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.ddBorder(
|
.doubleBorder(
|
||||||
inner = remember { RoundedCornerShape(size = 8.dp) },
|
inner = remember { RoundedCornerShape(size = 8.dp) },
|
||||||
outline = remember { CutCornerShape(size = 16.dp) },
|
outline = remember { CutCornerShape(size = 16.dp) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ fun lightColorScheme(
|
||||||
secondary = BaseColorPalette.Teal80,
|
secondary = BaseColorPalette.Teal80,
|
||||||
tertiary = BaseColorPalette.Teal40,
|
tertiary = BaseColorPalette.Teal40,
|
||||||
onPrimary = Color.White,
|
onPrimary = Color.White,
|
||||||
surfaceTint = BaseColorPalette.Purple40,
|
surfaceTint = Color.Gray,
|
||||||
),
|
),
|
||||||
placeholder: Color = Color(red = 230, green = 225, blue = 229),
|
placeholder: Color = Color(red = 230, green = 225, blue = 229),
|
||||||
sheet: LexiconColors.CharacterSheet = LexiconColors.CharacterSheet(
|
sheet: LexiconColors.CharacterSheet = LexiconColors.CharacterSheet(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,287 @@
|
||||||
|
package com.pixelized.rplexicon.utilitary
|
||||||
|
|
||||||
|
import androidx.compose.animation.core.Animatable
|
||||||
|
import androidx.compose.animation.core.Spring
|
||||||
|
import androidx.compose.animation.core.VectorConverter
|
||||||
|
import androidx.compose.animation.core.VisibilityThreshold
|
||||||
|
import androidx.compose.animation.core.spring
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.gestures.scrollBy
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyGridItemInfo
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyGridItemScope
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyGridState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Size
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.compose.ui.unit.IntSize
|
||||||
|
import androidx.compose.ui.unit.toOffset
|
||||||
|
import androidx.compose.ui.unit.toSize
|
||||||
|
import androidx.compose.ui.zIndex
|
||||||
|
import com.pixelized.rplexicon.utilitary.lazyGridDragAndDrop.detectDragGesturesAfterLongPress
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/***
|
||||||
|
* https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LazyGridDragAndDropDemo.kt
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun rememberGridDragDropState(
|
||||||
|
contentPadding: PaddingValues,
|
||||||
|
gridState: LazyGridState,
|
||||||
|
onMove: (Int, Int) -> Unit,
|
||||||
|
onOver: (Int, Int) -> Boolean,
|
||||||
|
onDrop: (Int, Int) -> Unit,
|
||||||
|
): GridDragDropState {
|
||||||
|
val density = LocalDensity.current
|
||||||
|
val layoutDirection = LocalLayoutDirection.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val currentOnMove = rememberUpdatedState(newValue = onMove)
|
||||||
|
val currentOnOver = rememberUpdatedState(newValue = onOver)
|
||||||
|
val currentOnDrop = rememberUpdatedState(newValue = onDrop)
|
||||||
|
|
||||||
|
val state = remember(gridState, scope, currentOnMove) {
|
||||||
|
GridDragDropState(
|
||||||
|
contentOffset = with(density) {
|
||||||
|
Offset(
|
||||||
|
contentPadding.calculateTopPadding().toPx(),
|
||||||
|
contentPadding.calculateLeftPadding(layoutDirection).toPx()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
scope = scope,
|
||||||
|
state = gridState,
|
||||||
|
onMove = currentOnMove.value,
|
||||||
|
onOver = currentOnOver.value,
|
||||||
|
onDrop = currentOnDrop.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
while (isActive) {
|
||||||
|
val diff = state.scrollChannel.receive()
|
||||||
|
gridState.scrollBy(diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
class GridDragDropState internal constructor(
|
||||||
|
private val contentOffset: Offset,
|
||||||
|
private val scope: CoroutineScope,
|
||||||
|
private val state: LazyGridState,
|
||||||
|
private val onMove: (Int, Int) -> Unit,
|
||||||
|
private val onOver: (Int, Int) -> Boolean,
|
||||||
|
private val onDrop: (Int, Int) -> Unit,
|
||||||
|
) {
|
||||||
|
internal val scrollChannel = Channel<Float>()
|
||||||
|
|
||||||
|
var draggingItemIndex by mutableStateOf<Int?>(null)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var overItemIndex by mutableStateOf<Int?>(null)
|
||||||
|
private set
|
||||||
|
|
||||||
|
private var draggingItemInitialOffset by mutableStateOf(Offset.Zero)
|
||||||
|
|
||||||
|
private var draggingItemDraggedDelta by mutableStateOf(Offset.Zero)
|
||||||
|
|
||||||
|
internal val draggingItemOffset: Offset
|
||||||
|
get() = draggingItemLayoutInfo
|
||||||
|
?.let { item -> draggingItemInitialOffset + draggingItemDraggedDelta - item.offset.toOffset() }
|
||||||
|
?: Offset.Zero
|
||||||
|
|
||||||
|
private val draggingItemLayoutInfo: LazyGridItemInfo?
|
||||||
|
get() = state.layoutInfo.visibleItemsInfo
|
||||||
|
.firstOrNull { it.index == draggingItemIndex }
|
||||||
|
|
||||||
|
internal var previousIndexOfDraggedItem by mutableStateOf<Int?>(null)
|
||||||
|
private set
|
||||||
|
|
||||||
|
internal var previousItemOffset = Animatable(Offset.Zero, Offset.VectorConverter)
|
||||||
|
private set
|
||||||
|
|
||||||
|
internal fun onDragStart(offset: Offset) {
|
||||||
|
state.layoutInfo.visibleItemsInfo
|
||||||
|
.firstItemWithOffsetOrNull(offset = offset)
|
||||||
|
?.let {
|
||||||
|
draggingItemIndex = it.index
|
||||||
|
draggingItemInitialOffset = it.offset.toOffset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun onDragInterrupted(offset: Offset) {
|
||||||
|
val localDraggingItemIndex = draggingItemIndex
|
||||||
|
if (localDraggingItemIndex != null) {
|
||||||
|
state.layoutInfo.visibleItemsInfo
|
||||||
|
.firstItemWithOffsetOrNull(offset)
|
||||||
|
?.let { onDrop(localDraggingItemIndex, it.index) }
|
||||||
|
|
||||||
|
previousIndexOfDraggedItem = draggingItemIndex
|
||||||
|
val startOffset = draggingItemOffset
|
||||||
|
scope.launch {
|
||||||
|
previousItemOffset.snapTo(startOffset)
|
||||||
|
previousItemOffset.animateTo(
|
||||||
|
Offset.Zero,
|
||||||
|
spring(
|
||||||
|
stiffness = Spring.StiffnessMediumLow,
|
||||||
|
visibilityThreshold = Offset.VisibilityThreshold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
previousIndexOfDraggedItem = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overItemIndex = null
|
||||||
|
draggingItemDraggedDelta = Offset.Zero
|
||||||
|
draggingItemIndex = null
|
||||||
|
draggingItemInitialOffset = Offset.Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun onDrag(offset: Offset) {
|
||||||
|
draggingItemDraggedDelta += offset
|
||||||
|
|
||||||
|
val draggingItem = draggingItemLayoutInfo ?: return
|
||||||
|
val startOffset = draggingItem.offset.toOffset() + draggingItemOffset
|
||||||
|
val endOffset = startOffset + draggingItem.size.toSize()
|
||||||
|
|
||||||
|
val middleOffset = startOffset + (endOffset - startOffset) / 2f
|
||||||
|
val middleXOffset = middleOffset.x.toInt()
|
||||||
|
val middleYOffset = middleOffset.y.toInt()
|
||||||
|
|
||||||
|
val targetItem = state.layoutInfo.visibleItemsInfo.find { item ->
|
||||||
|
draggingItem.index != item.index &&
|
||||||
|
item.offset.x <= middleXOffset && middleXOffset <= item.offsetEnd.x &&
|
||||||
|
item.offset.y <= middleYOffset && middleYOffset <= item.offsetEnd.y
|
||||||
|
}
|
||||||
|
|
||||||
|
overItemIndex = targetItem?.index
|
||||||
|
|
||||||
|
if (targetItem != null) {
|
||||||
|
if (onOver.invoke(draggingItem.index, targetItem.index)) {
|
||||||
|
onMove.invoke(draggingItem.index, targetItem.index)
|
||||||
|
draggingItemIndex = targetItem.index
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val overscroll = when {
|
||||||
|
draggingItemDraggedDelta.y > 0 ->
|
||||||
|
(endOffset.y - state.layoutInfo.viewportEndOffset).coerceAtLeast(0f)
|
||||||
|
|
||||||
|
draggingItemDraggedDelta.y < 0 ->
|
||||||
|
(startOffset.y - state.layoutInfo.viewportStartOffset).coerceAtMost(0f)
|
||||||
|
|
||||||
|
else -> 0f
|
||||||
|
}
|
||||||
|
if (overscroll != 0f) {
|
||||||
|
scrollChannel.trySend(overscroll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<LazyGridItemInfo>.firstItemWithOffsetOrNull(
|
||||||
|
offset: Offset,
|
||||||
|
): LazyGridItemInfo? {
|
||||||
|
val offsetX = offset.x.toInt() - contentOffset.x.toInt()
|
||||||
|
val offsetY = offset.y.toInt() - contentOffset.y.toInt()
|
||||||
|
return this.firstOrNull { item ->
|
||||||
|
item.offset.x <= offsetX && offsetX <= item.offsetEnd.x &&
|
||||||
|
item.offset.y <= offsetY && offsetY <= item.offsetEnd.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val LazyGridItemInfo.offsetEnd: IntOffset
|
||||||
|
get() = this.offset + this.size
|
||||||
|
}
|
||||||
|
|
||||||
|
private operator fun IntOffset.plus(size: IntSize): IntOffset {
|
||||||
|
return IntOffset(x + size.width, y + size.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
private operator fun Offset.plus(size: Size): Offset {
|
||||||
|
return Offset(x + size.width, y + size.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Modifier.dragContainer(dragDropState: GridDragDropState): Modifier {
|
||||||
|
return this then Modifier.pointerInput(dragDropState) {
|
||||||
|
detectDragGesturesAfterLongPress(
|
||||||
|
onDrag = { change, offset ->
|
||||||
|
change.consume()
|
||||||
|
dragDropState.onDrag(offset = offset)
|
||||||
|
},
|
||||||
|
onDragStart = { offset ->
|
||||||
|
dragDropState.onDragStart(offset)
|
||||||
|
},
|
||||||
|
onDragEnd = { offset ->
|
||||||
|
dragDropState.onDragInterrupted(offset)
|
||||||
|
},
|
||||||
|
onDragCancel = {
|
||||||
|
dragDropState.onDragInterrupted(Offset.Zero)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun LazyGridItemScope.DraggableItem(
|
||||||
|
dragDropState: GridDragDropState,
|
||||||
|
index: Int,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
content: @Composable (isDragging: Boolean, isOver: Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
val dragging by remember(index, dragDropState) {
|
||||||
|
derivedStateOf {
|
||||||
|
index == dragDropState.draggingItemIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val overing by remember(index, dragDropState) {
|
||||||
|
derivedStateOf {
|
||||||
|
index == dragDropState.overItemIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val draggingModifier = when {
|
||||||
|
dragging -> {
|
||||||
|
Modifier
|
||||||
|
.zIndex(1f)
|
||||||
|
.graphicsLayer {
|
||||||
|
translationX = dragDropState.draggingItemOffset.x
|
||||||
|
translationY = dragDropState.draggingItemOffset.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index == dragDropState.previousIndexOfDraggedItem -> {
|
||||||
|
Modifier
|
||||||
|
.zIndex(1f)
|
||||||
|
.graphicsLayer {
|
||||||
|
translationX = dragDropState.previousItemOffset.value.x
|
||||||
|
translationY = dragDropState.previousItemOffset.value.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
Modifier.animateItemPlacement()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = modifier.then(draggingModifier),
|
||||||
|
propagateMinConstraints = true,
|
||||||
|
) {
|
||||||
|
content(dragging, overing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,6 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.surfaceColorAtElevation
|
import androidx.compose.material3.surfaceColorAtElevation
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -106,7 +105,7 @@ fun Modifier.clickableInterceptor(): Modifier = composed {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Modifier.ddBorder(
|
fun Modifier.doubleBorder(
|
||||||
horizontalSpacing: Dp = 3.dp,
|
horizontalSpacing: Dp = 3.dp,
|
||||||
verticalSpacing: Dp = 3.dp,
|
verticalSpacing: Dp = 3.dp,
|
||||||
outline: Shape,
|
outline: Shape,
|
||||||
|
|
@ -114,37 +113,38 @@ fun Modifier.ddBorder(
|
||||||
inner: Shape,
|
inner: Shape,
|
||||||
innerWidth: Dp = 1.dp,
|
innerWidth: Dp = 1.dp,
|
||||||
): Modifier = composed {
|
): Modifier = composed {
|
||||||
val isDarkTheme = isInDarkTheme()
|
|
||||||
val elevation = remember { derivedStateOf { if (isDarkTheme) 2.dp else 0.dp } }
|
|
||||||
val colorScheme = MaterialTheme.lexicon.colorScheme
|
val colorScheme = MaterialTheme.lexicon.colorScheme
|
||||||
this then Modifier
|
this then Modifier.doubleBorder(
|
||||||
.border(
|
horizontalSpacing = horizontalSpacing,
|
||||||
width = outlineWidth,
|
verticalSpacing = verticalSpacing,
|
||||||
color = colorScheme.characterSheet.outlineBorder,
|
backgroundColor = colorScheme.base.surfaceColorAtElevation(1.dp),
|
||||||
shape = outline,
|
outline = outline,
|
||||||
)
|
outlineWidth = outlineWidth,
|
||||||
.background(
|
outlineColor = colorScheme.characterSheet.outlineBorder,
|
||||||
shape = outline,
|
inner = inner,
|
||||||
color = colorScheme.base.surfaceColorAtElevation(elevation.value)
|
innerWidth = innerWidth,
|
||||||
)
|
innerColor = colorScheme.characterSheet.innerBorder,
|
||||||
.padding(
|
)
|
||||||
horizontal = horizontalSpacing,
|
|
||||||
vertical = verticalSpacing,
|
|
||||||
)
|
|
||||||
.border(
|
|
||||||
width = innerWidth,
|
|
||||||
color = colorScheme.characterSheet.innerBorder,
|
|
||||||
shape = inner,
|
|
||||||
)
|
|
||||||
.background(
|
|
||||||
shape = inner,
|
|
||||||
color = colorScheme.base.surfaceColorAtElevation(elevation.value)
|
|
||||||
)
|
|
||||||
.clip(
|
|
||||||
shape = inner,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Modifier.doubleBorder(
|
||||||
|
horizontalSpacing: Dp = 3.dp,
|
||||||
|
verticalSpacing: Dp = 3.dp,
|
||||||
|
backgroundColor: Color,
|
||||||
|
outline: Shape,
|
||||||
|
outlineWidth: Dp = 1.dp,
|
||||||
|
outlineColor: Color,
|
||||||
|
inner: Shape,
|
||||||
|
innerWidth: Dp = 1.dp,
|
||||||
|
innerColor: Color,
|
||||||
|
): Modifier = this then Modifier
|
||||||
|
.border(width = outlineWidth, color = outlineColor, shape = outline)
|
||||||
|
.background(shape = outline, color = backgroundColor)
|
||||||
|
.padding(horizontal = horizontalSpacing, vertical = verticalSpacing)
|
||||||
|
.border(width = innerWidth, color = innerColor, shape = inner)
|
||||||
|
.background(shape = inner, color = backgroundColor)
|
||||||
|
.clip(shape = inner)
|
||||||
|
|
||||||
fun Modifier.lexiconShadow(): Modifier {
|
fun Modifier.lexiconShadow(): Modifier {
|
||||||
return this then composed {
|
return this then composed {
|
||||||
val isDarkTheme = isInDarkTheme()
|
val isDarkTheme = isInDarkTheme()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.pixelized.rplexicon.utilitary.lazyGridDragAndDrop
|
||||||
|
|
||||||
|
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||||
|
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||||
|
import androidx.compose.foundation.gestures.awaitLongPressOrCancellation
|
||||||
|
import androidx.compose.foundation.gestures.drag
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.input.pointer.PointerInputChange
|
||||||
|
import androidx.compose.ui.input.pointer.PointerInputScope
|
||||||
|
import androidx.compose.ui.input.pointer.changedToUp
|
||||||
|
import androidx.compose.ui.input.pointer.positionChange
|
||||||
|
import androidx.compose.ui.util.fastForEach
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
|
||||||
|
suspend fun PointerInputScope.detectDragGesturesAfterLongPress(
|
||||||
|
onDragStart: (Offset) -> Unit = { },
|
||||||
|
onDragEnd: (Offset) -> Unit = { },
|
||||||
|
onDragCancel: () -> Unit = { },
|
||||||
|
onDrag: (change: PointerInputChange, dragAmount: Offset) -> Unit
|
||||||
|
) {
|
||||||
|
awaitEachGesture {
|
||||||
|
try {
|
||||||
|
// await for a press
|
||||||
|
val down = awaitFirstDown(requireUnconsumed = false)
|
||||||
|
// await for a long press or a cancellation
|
||||||
|
val drag = awaitLongPressOrCancellation(pointerId = down.id)
|
||||||
|
// if the user did a long press
|
||||||
|
if (drag != null) {
|
||||||
|
// callback onDragStart with the initial position.
|
||||||
|
onDragStart.invoke(drag.position)
|
||||||
|
var lastDragInput: PointerInputChange = drag
|
||||||
|
val dragEnded = drag(
|
||||||
|
pointerId = drag.id,
|
||||||
|
onDrag = { input ->
|
||||||
|
lastDragInput = input
|
||||||
|
onDrag(input, input.positionChange())
|
||||||
|
input.consume()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (dragEnded) {
|
||||||
|
// consume up if we quit drag gracefully with the up
|
||||||
|
currentEvent.changes.fastForEach {
|
||||||
|
if (it.changedToUp()) it.consume()
|
||||||
|
}
|
||||||
|
onDragEnd(lastDragInput.position)
|
||||||
|
} else {
|
||||||
|
onDragCancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (c: CancellationException) {
|
||||||
|
onDragCancel()
|
||||||
|
throw c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
app/src/main/res/drawable/icbg_pouch_a_unfaded.webp
Normal file
BIN
app/src/main/res/drawable/icbg_pouch_a_unfaded.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Loading…
Add table
Add a link
Reference in a new issue