Realigning reactions
This commit is contained in:
@@ -20,12 +20,22 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.actions
|
package com.vitorpamplona.amethyst.ui.actions
|
||||||
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.animation.core.FiniteAnimationSpec
|
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||||
|
import androidx.compose.animation.core.Transition
|
||||||
|
import androidx.compose.animation.core.animateFloat
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.core.updateTransition
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.key
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.util.fastForEach
|
||||||
import com.vitorpamplona.amethyst.model.FeatureSetType
|
import com.vitorpamplona.amethyst.model.FeatureSetType
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
|
||||||
@@ -33,16 +43,86 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
|||||||
fun <T> CrossfadeIfEnabled(
|
fun <T> CrossfadeIfEnabled(
|
||||||
targetState: T,
|
targetState: T,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
contentAlignment: Alignment = Alignment.TopStart,
|
||||||
animationSpec: FiniteAnimationSpec<Float> = tween(),
|
animationSpec: FiniteAnimationSpec<Float> = tween(),
|
||||||
label: String = "Crossfade",
|
label: String = "Crossfade",
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
content: @Composable (T) -> Unit,
|
content: @Composable (T) -> Unit,
|
||||||
) {
|
) {
|
||||||
if (accountViewModel.settings.featureSet == FeatureSetType.PERFORMANCE) {
|
if (accountViewModel.settings.featureSet == FeatureSetType.PERFORMANCE) {
|
||||||
Box(modifier) {
|
Box(modifier, contentAlignment) {
|
||||||
content(targetState)
|
content(targetState)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Crossfade(targetState, modifier, animationSpec, label, content)
|
MyCrossfade(targetState, modifier, contentAlignment, animationSpec, label, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalAnimationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun <T> MyCrossfade(
|
||||||
|
targetState: T,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
contentAlignment: Alignment = Alignment.TopStart,
|
||||||
|
animationSpec: FiniteAnimationSpec<Float> = tween(),
|
||||||
|
label: String = "Crossfade",
|
||||||
|
content: @Composable (T) -> Unit,
|
||||||
|
) {
|
||||||
|
val transition = updateTransition(targetState, label)
|
||||||
|
transition.MyCrossfade(modifier, contentAlignment, animationSpec, content = content)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalAnimationApi
|
||||||
|
@Composable
|
||||||
|
fun <T> Transition<T>.MyCrossfade(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
contentAlignment: Alignment = Alignment.TopStart,
|
||||||
|
animationSpec: FiniteAnimationSpec<Float> = tween(),
|
||||||
|
contentKey: (targetState: T) -> Any? = { it },
|
||||||
|
content: @Composable (targetState: T) -> Unit,
|
||||||
|
) {
|
||||||
|
val currentlyVisible = remember { mutableStateListOf<T>().apply { add(currentState) } }
|
||||||
|
val contentMap =
|
||||||
|
remember {
|
||||||
|
mutableMapOf<T, @Composable () -> Unit>()
|
||||||
|
}
|
||||||
|
if (currentState == targetState) {
|
||||||
|
// If not animating, just display the current state
|
||||||
|
if (currentlyVisible.size != 1 || currentlyVisible[0] != targetState) {
|
||||||
|
// Remove all the intermediate items from the list once the animation is finished.
|
||||||
|
currentlyVisible.removeAll { it != targetState }
|
||||||
|
contentMap.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!contentMap.contains(targetState)) {
|
||||||
|
// Replace target with the same key if any
|
||||||
|
val replacementId =
|
||||||
|
currentlyVisible.indexOfFirst {
|
||||||
|
contentKey(it) == contentKey(targetState)
|
||||||
|
}
|
||||||
|
if (replacementId == -1) {
|
||||||
|
currentlyVisible.add(targetState)
|
||||||
|
} else {
|
||||||
|
currentlyVisible[replacementId] = targetState
|
||||||
|
}
|
||||||
|
contentMap.clear()
|
||||||
|
currentlyVisible.fastForEach { stateForContent ->
|
||||||
|
contentMap[stateForContent] = {
|
||||||
|
val alpha by animateFloat(
|
||||||
|
transitionSpec = { animationSpec },
|
||||||
|
) { if (it == stateForContent) 1f else 0f }
|
||||||
|
Box(Modifier.graphicsLayer { this.alpha = alpha }, contentAlignment) {
|
||||||
|
content(stateForContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(modifier, contentAlignment) {
|
||||||
|
currentlyVisible.fastForEach {
|
||||||
|
key(contentKey(it)) {
|
||||||
|
contentMap[it]?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.components
|
package com.vitorpamplona.amethyst.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
@@ -33,7 +35,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size24dp
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ClickableBox(
|
fun ClickableBox(
|
||||||
modifier: Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -49,3 +51,25 @@ fun ClickableBox(
|
|||||||
content()
|
content()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun ClickableBox(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
onLongClick: () -> Unit,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier.combinedClickable(
|
||||||
|
role = Role.Button,
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
indication = rememberRipple(bounded = false, radius = Size24dp),
|
||||||
|
onClick = onClick,
|
||||||
|
onLongClick = onLongClick,
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import androidx.compose.animation.slideOutVertically
|
|||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -49,13 +48,15 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Cancel
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ElevatedCard
|
import androidx.compose.material3.ElevatedCard
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ProgressIndicatorDefaults
|
import androidx.compose.material3.ProgressIndicatorDefaults
|
||||||
@@ -85,6 +86,7 @@ import androidx.compose.ui.platform.LocalDensity
|
|||||||
import androidx.compose.ui.semantics.Role
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.TextUnit
|
import androidx.compose.ui.unit.TextUnit
|
||||||
@@ -112,6 +114,7 @@ import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.DarkerGreen
|
import com.vitorpamplona.amethyst.ui.theme.DarkerGreen
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer
|
import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ModifierWidth3dp
|
import com.vitorpamplona.amethyst.ui.theme.ModifierWidth3dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.NoSoTinyBorders
|
import com.vitorpamplona.amethyst.ui.theme.NoSoTinyBorders
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ReactionRowExpandButton
|
import com.vitorpamplona.amethyst.ui.theme.ReactionRowExpandButton
|
||||||
@@ -127,6 +130,8 @@ import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size22Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size22Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size24dp
|
import com.vitorpamplona.amethyst.ui.theme.Size24dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.SmallBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||||
import com.vitorpamplona.amethyst.ui.theme.TinyBorders
|
import com.vitorpamplona.amethyst.ui.theme.TinyBorders
|
||||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
@@ -135,6 +140,7 @@ import com.vitorpamplona.quartz.events.BaseTextNoteEvent
|
|||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.persistentSetOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableSet
|
import kotlinx.collections.immutable.toImmutableSet
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -831,14 +837,7 @@ fun LikeReaction(
|
|||||||
var wantsToChangeReactionSymbol by remember { mutableStateOf(false) }
|
var wantsToChangeReactionSymbol by remember { mutableStateOf(false) }
|
||||||
var wantsToReact by remember { mutableStateOf(false) }
|
var wantsToReact by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Box(
|
ClickableBox(
|
||||||
contentAlignment = Center,
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.combinedClickable(
|
|
||||||
role = Role.Button,
|
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
|
||||||
indication = rememberRipple(bounded = false, radius = Size24dp),
|
|
||||||
onClick = {
|
onClick = {
|
||||||
likeClick(
|
likeClick(
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
@@ -848,12 +847,11 @@ fun LikeReaction(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
onLongClick = { wantsToChangeReactionSymbol = true },
|
onLongClick = { wantsToChangeReactionSymbol = true },
|
||||||
),
|
|
||||||
) {
|
) {
|
||||||
ObserveLikeIcon(baseNote, accountViewModel) { reactionType ->
|
ObserveLikeIcon(baseNote, accountViewModel) { reactionType ->
|
||||||
CrossfadeIfEnabled(targetState = reactionType, label = "LikeIcon", accountViewModel = accountViewModel) {
|
CrossfadeIfEnabled(targetState = reactionType, contentAlignment = Center, label = "LikeIcon", accountViewModel = accountViewModel) {
|
||||||
if (it != null) {
|
if (reactionType != null) {
|
||||||
RenderReactionType(it, heartSizeModifier, iconFontSize)
|
RenderReactionType(reactionType, heartSizeModifier, iconFontSize)
|
||||||
} else {
|
} else {
|
||||||
LikeIcon(heartSizeModifier, grayTint)
|
LikeIcon(heartSizeModifier, grayTint)
|
||||||
}
|
}
|
||||||
@@ -1320,6 +1318,7 @@ fun ReactionChoicePopup(
|
|||||||
val account = accountState?.account ?: return
|
val account = accountState?.account ?: return
|
||||||
|
|
||||||
val toRemove = remember { baseNote.reactedBy(account.userProfile()).toImmutableSet() }
|
val toRemove = remember { baseNote.reactedBy(account.userProfile()).toImmutableSet() }
|
||||||
|
val reactions = remember { account.reactionChoices.toImmutableList() }
|
||||||
|
|
||||||
val iconSizePx = with(LocalDensity.current) { -iconSize.toPx().toInt() }
|
val iconSizePx = with(LocalDensity.current) { -iconSize.toPx().toInt() }
|
||||||
|
|
||||||
@@ -1328,107 +1327,138 @@ fun ReactionChoicePopup(
|
|||||||
offset = IntOffset(0, iconSizePx),
|
offset = IntOffset(0, iconSizePx),
|
||||||
onDismissRequest = { onDismiss() },
|
onDismissRequest = { onDismiss() },
|
||||||
) {
|
) {
|
||||||
ElevatedCard(
|
ReactionChoicePopupContent(
|
||||||
Modifier
|
reactions,
|
||||||
.border(width = 1.dp, color = MaterialTheme.colorScheme.outline, shape = RoundedCornerShape(5.dp)),
|
toRemove = toRemove,
|
||||||
elevation = CardDefaults.elevatedCardElevation(defaultElevation = 8.dp),
|
onClick = { reactionType ->
|
||||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
|
|
||||||
) {
|
|
||||||
Box(modifier = Modifier.padding(5.dp)) {
|
|
||||||
FlowRow(horizontalArrangement = Arrangement.Center) {
|
|
||||||
account.reactionChoices.forEach { reactionType ->
|
|
||||||
ActionableReactionButton(
|
|
||||||
baseNote,
|
|
||||||
reactionType,
|
|
||||||
accountViewModel,
|
|
||||||
onDismiss,
|
|
||||||
onChangeAmount,
|
|
||||||
toRemove,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
private fun ActionableReactionButton(
|
|
||||||
baseNote: Note,
|
|
||||||
reactionType: String,
|
|
||||||
accountViewModel: AccountViewModel,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
onChangeAmount: () -> Unit,
|
|
||||||
toRemove: ImmutableSet<String>,
|
|
||||||
) {
|
|
||||||
val thisModifier =
|
|
||||||
remember(reactionType) {
|
|
||||||
Modifier
|
|
||||||
.padding(horizontal = 3.dp)
|
|
||||||
.combinedClickable(
|
|
||||||
onClick = {
|
|
||||||
accountViewModel.reactToOrDelete(
|
accountViewModel.reactToOrDelete(
|
||||||
baseNote,
|
baseNote,
|
||||||
reactionType,
|
reactionType,
|
||||||
)
|
)
|
||||||
onDismiss()
|
onDismiss()
|
||||||
},
|
},
|
||||||
onLongClick = { onChangeAmount() },
|
onChangeAmount,
|
||||||
)
|
)
|
||||||
.padding(5.dp)
|
|
||||||
}
|
|
||||||
|
|
||||||
val removeSymbol =
|
|
||||||
remember(reactionType) {
|
|
||||||
if (reactionType in toRemove) {
|
|
||||||
" ✖"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
@Composable
|
||||||
|
fun ReactionChoicePopupContent(
|
||||||
|
listOfReactions: ImmutableList<String>,
|
||||||
|
toRemove: ImmutableSet<String>,
|
||||||
|
onClick: (reactionType: String) -> Unit,
|
||||||
|
onChangeAmount: () -> Unit,
|
||||||
|
) {
|
||||||
|
Box(HalfPadding, contentAlignment = Center) {
|
||||||
|
ElevatedCard(
|
||||||
|
shape = SmallBorder,
|
||||||
|
elevation = CardDefaults.elevatedCardElevation(defaultElevation = 8.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
|
||||||
|
) {
|
||||||
|
FlowRow(
|
||||||
|
modifier = HalfPadding,
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
) {
|
||||||
|
listOfReactions.forEach { reactionType ->
|
||||||
|
ActionableReactionButton(
|
||||||
|
reactionType = reactionType,
|
||||||
|
onClick = { onClick(reactionType) },
|
||||||
|
onChangeAmount = onChangeAmount,
|
||||||
|
toRemove = toRemove,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview()
|
||||||
|
@Composable
|
||||||
|
fun ReactionChoicePopupPeeview() {
|
||||||
|
ThemeComparisonColumn {
|
||||||
|
ReactionChoicePopupContent(
|
||||||
|
persistentListOf(
|
||||||
|
"\uD83D\uDE80",
|
||||||
|
"\uD83E\uDEC2",
|
||||||
|
"\uD83D\uDC40",
|
||||||
|
"\uD83D\uDE02",
|
||||||
|
"\uD83C\uDF89",
|
||||||
|
"\uD83E\uDD14",
|
||||||
|
"\uD83D\uDE31",
|
||||||
|
"\uD83E\uDD14",
|
||||||
|
"\uD83D\uDE31",
|
||||||
|
"+",
|
||||||
|
"-",
|
||||||
|
),
|
||||||
|
onClick = {},
|
||||||
|
onChangeAmount = {},
|
||||||
|
toRemove = persistentSetOf(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
private fun ActionableReactionButton(
|
||||||
|
reactionType: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
onChangeAmount: () -> Unit,
|
||||||
|
toRemove: ImmutableSet<String>,
|
||||||
|
) {
|
||||||
|
val thisModifier =
|
||||||
|
Modifier
|
||||||
|
.padding(horizontal = 8.dp, vertical = 5.dp)
|
||||||
|
.height(Size20dp)
|
||||||
|
.combinedClickable(
|
||||||
|
role = Role.Button,
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
indication = rememberRipple(bounded = false, radius = Size24dp),
|
||||||
|
onClick = onClick,
|
||||||
|
onLongClick = onChangeAmount,
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(thisModifier, verticalAlignment = Alignment.CenterVertically) {
|
||||||
if (reactionType.startsWith(":")) {
|
if (reactionType.startsWith(":")) {
|
||||||
val noStartColon = reactionType.removePrefix(":")
|
val noStartColon = reactionType.removePrefix(":")
|
||||||
val url = noStartColon.substringAfter(":")
|
val url = noStartColon.substringAfter(":")
|
||||||
|
|
||||||
val renderable =
|
InLineIconRenderer(
|
||||||
persistentListOf(
|
persistentListOf(
|
||||||
Nip30CustomEmoji.ImageUrlType(url),
|
Nip30CustomEmoji.ImageUrlType(url),
|
||||||
Nip30CustomEmoji.TextType(removeSymbol),
|
),
|
||||||
)
|
style = SpanStyle(color = MaterialTheme.colorScheme.onBackground),
|
||||||
|
|
||||||
InLineIconRenderer(
|
|
||||||
renderable,
|
|
||||||
style = SpanStyle(color = Color.White),
|
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
modifier = thisModifier,
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
when (reactionType) {
|
when (reactionType) {
|
||||||
"+" -> {
|
"+" -> {
|
||||||
LikedIcon(modifier = thisModifier.size(16.dp), tint = Color.White)
|
LikedIcon(modifier = Modifier.size(20.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
"-" -> {
|
||||||
Text(
|
Text(
|
||||||
text = removeSymbol,
|
text = "\uD83D\uDC4E",
|
||||||
color = Color.White,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
textAlign = TextAlign.Center,
|
maxLines = 1,
|
||||||
modifier = thisModifier,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"-" ->
|
else -> {
|
||||||
Text(
|
Text(
|
||||||
text = "\uD83D\uDC4E$removeSymbol",
|
"$reactionType",
|
||||||
color = Color.White,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
textAlign = TextAlign.Center,
|
maxLines = 1,
|
||||||
modifier = thisModifier,
|
|
||||||
)
|
)
|
||||||
else ->
|
}
|
||||||
Text(
|
}
|
||||||
"$reactionType$removeSymbol",
|
}
|
||||||
color = Color.White,
|
|
||||||
textAlign = TextAlign.Center,
|
if (reactionType in toRemove) {
|
||||||
modifier = thisModifier,
|
Icon(
|
||||||
|
imageVector = Icons.Default.Cancel,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.padding(start = 2.dp).size(14.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,18 +94,12 @@ private val LightLessImportantLink = LightColorPalette.primary.copy(alpha = 0.52
|
|||||||
private val DarkMediumImportantLink = DarkColorPalette.primary.copy(alpha = 0.32f)
|
private val DarkMediumImportantLink = DarkColorPalette.primary.copy(alpha = 0.32f)
|
||||||
private val LightMediumImportantLink = LightColorPalette.primary.copy(alpha = 0.32f)
|
private val LightMediumImportantLink = LightColorPalette.primary.copy(alpha = 0.32f)
|
||||||
|
|
||||||
private val DarkVeryImportantLink = DarkColorPalette.primary.copy(alpha = 0.12f)
|
|
||||||
private val LightVeryImportantLink = LightColorPalette.primary.copy(alpha = 0.12f)
|
|
||||||
|
|
||||||
private val DarkGrayText = DarkColorPalette.onSurface.copy(alpha = 0.52f)
|
private val DarkGrayText = DarkColorPalette.onSurface.copy(alpha = 0.52f)
|
||||||
private val LightGrayText = LightColorPalette.onSurface.copy(alpha = 0.52f)
|
private val LightGrayText = LightColorPalette.onSurface.copy(alpha = 0.52f)
|
||||||
|
|
||||||
private val DarkPlaceholderText = DarkColorPalette.onSurface.copy(alpha = 0.32f)
|
private val DarkPlaceholderText = DarkColorPalette.onSurface.copy(alpha = 0.32f)
|
||||||
private val LightPlaceholderText = LightColorPalette.onSurface.copy(alpha = 0.32f)
|
private val LightPlaceholderText = LightColorPalette.onSurface.copy(alpha = 0.32f)
|
||||||
|
|
||||||
private val DarkPlaceholderTextColorFilter = ColorFilter.tint(DarkPlaceholderText)
|
|
||||||
private val LightPlaceholderTextColorFilter = ColorFilter.tint(LightPlaceholderText)
|
|
||||||
|
|
||||||
private val DarkOnBackgroundColorFilter = ColorFilter.tint(DarkColorPalette.onBackground)
|
private val DarkOnBackgroundColorFilter = ColorFilter.tint(DarkColorPalette.onBackground)
|
||||||
private val LightOnBackgroundColorFilter = ColorFilter.tint(LightColorPalette.onBackground)
|
private val LightOnBackgroundColorFilter = ColorFilter.tint(LightColorPalette.onBackground)
|
||||||
|
|
||||||
@@ -115,20 +109,9 @@ private val LightSubtleButton = LightColorPalette.onSurface.copy(alpha = 0.22f)
|
|||||||
private val DarkSubtleBorder = DarkColorPalette.onSurface.copy(alpha = 0.12f)
|
private val DarkSubtleBorder = DarkColorPalette.onSurface.copy(alpha = 0.12f)
|
||||||
private val LightSubtleBorder = LightColorPalette.onSurface.copy(alpha = 0.12f)
|
private val LightSubtleBorder = LightColorPalette.onSurface.copy(alpha = 0.12f)
|
||||||
|
|
||||||
private val DarkReplyItemBackground = DarkColorPalette.onSurface.copy(alpha = 0.05f)
|
|
||||||
private val LightReplyItemBackground = LightColorPalette.onSurface.copy(alpha = 0.05f)
|
|
||||||
|
|
||||||
private val DarkZapraiserBackground =
|
|
||||||
BitcoinOrange.copy(0.52f).compositeOver(DarkColorPalette.background)
|
|
||||||
private val LightZapraiserBackground =
|
|
||||||
BitcoinOrange.copy(0.52f).compositeOver(LightColorPalette.background)
|
|
||||||
|
|
||||||
private val DarkOverPictureBackground = DarkColorPalette.background.copy(0.62f)
|
private val DarkOverPictureBackground = DarkColorPalette.background.copy(0.62f)
|
||||||
private val LightOverPictureBackground = LightColorPalette.background.copy(0.62f)
|
private val LightOverPictureBackground = LightColorPalette.background.copy(0.62f)
|
||||||
|
|
||||||
val RepostPictureBorderDark = Modifier.border(2.dp, DarkColorPalette.background, CircleShape)
|
|
||||||
val RepostPictureBorderLight = Modifier.border(2.dp, LightColorPalette.background, CircleShape)
|
|
||||||
|
|
||||||
val DarkImageModifier =
|
val DarkImageModifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -225,16 +208,6 @@ val DarkLargeRelayIconModifier =
|
|||||||
.size(Size55dp)
|
.size(Size55dp)
|
||||||
.clip(shape = CircleShape)
|
.clip(shape = CircleShape)
|
||||||
|
|
||||||
val LightBottomIconModifier =
|
|
||||||
Modifier
|
|
||||||
.size(Size10dp)
|
|
||||||
.clip(shape = CircleShape)
|
|
||||||
|
|
||||||
val DarkBottomIconModifier =
|
|
||||||
Modifier
|
|
||||||
.size(Size10dp)
|
|
||||||
.clip(shape = CircleShape)
|
|
||||||
|
|
||||||
val RichTextDefaults = RichTextStyle().resolveDefaults()
|
val RichTextDefaults = RichTextStyle().resolveDefaults()
|
||||||
|
|
||||||
val MarkDownStyleOnDark =
|
val MarkDownStyleOnDark =
|
||||||
@@ -319,9 +292,6 @@ val ColorScheme.isLight: Boolean
|
|||||||
val ColorScheme.newItemBackgroundColor: Color
|
val ColorScheme.newItemBackgroundColor: Color
|
||||||
get() = if (isLight) LightNewItemBackground else DarkNewItemBackground
|
get() = if (isLight) LightNewItemBackground else DarkNewItemBackground
|
||||||
|
|
||||||
val ColorScheme.replyBackground: Color
|
|
||||||
get() = if (isLight) LightReplyItemBackground else DarkReplyItemBackground
|
|
||||||
|
|
||||||
val ColorScheme.selectedNote: Color
|
val ColorScheme.selectedNote: Color
|
||||||
get() = if (isLight) LightSelectedNote else DarkSelectedNote
|
get() = if (isLight) LightSelectedNote else DarkSelectedNote
|
||||||
|
|
||||||
@@ -331,13 +301,8 @@ val ColorScheme.secondaryButtonBackground: Color
|
|||||||
val ColorScheme.lessImportantLink: Color
|
val ColorScheme.lessImportantLink: Color
|
||||||
get() = if (isLight) LightLessImportantLink else DarkLessImportantLink
|
get() = if (isLight) LightLessImportantLink else DarkLessImportantLink
|
||||||
|
|
||||||
val ColorScheme.zapraiserBackground: Color
|
|
||||||
get() = if (isLight) LightZapraiserBackground else DarkZapraiserBackground
|
|
||||||
|
|
||||||
val ColorScheme.mediumImportanceLink: Color
|
val ColorScheme.mediumImportanceLink: Color
|
||||||
get() = if (isLight) LightMediumImportantLink else DarkMediumImportantLink
|
get() = if (isLight) LightMediumImportantLink else DarkMediumImportantLink
|
||||||
val ColorScheme.veryImportantLink: Color
|
|
||||||
get() = if (isLight) LightVeryImportantLink else DarkVeryImportantLink
|
|
||||||
|
|
||||||
val ColorScheme.placeholderText: Color
|
val ColorScheme.placeholderText: Color
|
||||||
get() = if (isLight) LightPlaceholderText else DarkPlaceholderText
|
get() = if (isLight) LightPlaceholderText else DarkPlaceholderText
|
||||||
@@ -345,9 +310,6 @@ val ColorScheme.placeholderText: Color
|
|||||||
val ColorScheme.nip05: Color
|
val ColorScheme.nip05: Color
|
||||||
get() = if (isLight) Nip05EmailColorLight else Nip05EmailColorDark
|
get() = if (isLight) Nip05EmailColorLight else Nip05EmailColorDark
|
||||||
|
|
||||||
val ColorScheme.placeholderTextColorFilter: ColorFilter
|
|
||||||
get() = if (isLight) LightPlaceholderTextColorFilter else DarkPlaceholderTextColorFilter
|
|
||||||
|
|
||||||
val ColorScheme.onBackgroundColorFilter: ColorFilter
|
val ColorScheme.onBackgroundColorFilter: ColorFilter
|
||||||
get() = if (isLight) LightOnBackgroundColorFilter else DarkOnBackgroundColorFilter
|
get() = if (isLight) LightOnBackgroundColorFilter else DarkOnBackgroundColorFilter
|
||||||
|
|
||||||
@@ -375,9 +337,6 @@ val ColorScheme.allGoodColor: Color
|
|||||||
val ColorScheme.markdownStyle: RichTextStyle
|
val ColorScheme.markdownStyle: RichTextStyle
|
||||||
get() = if (isLight) MarkDownStyleOnLight else MarkDownStyleOnDark
|
get() = if (isLight) MarkDownStyleOnLight else MarkDownStyleOnDark
|
||||||
|
|
||||||
val ColorScheme.repostProfileBorder: Modifier
|
|
||||||
get() = if (isLight) RepostPictureBorderLight else RepostPictureBorderDark
|
|
||||||
|
|
||||||
val ColorScheme.imageModifier: Modifier
|
val ColorScheme.imageModifier: Modifier
|
||||||
get() = if (isLight) LightImageModifier else DarkImageModifier
|
get() = if (isLight) LightImageModifier else DarkImageModifier
|
||||||
|
|
||||||
@@ -402,9 +361,6 @@ val ColorScheme.relayIconModifier: Modifier
|
|||||||
val ColorScheme.largeRelayIconModifier: Modifier
|
val ColorScheme.largeRelayIconModifier: Modifier
|
||||||
get() = if (isLight) LightLargeRelayIconModifier else DarkLargeRelayIconModifier
|
get() = if (isLight) LightLargeRelayIconModifier else DarkLargeRelayIconModifier
|
||||||
|
|
||||||
val ColorScheme.bottomIconModifier: Modifier
|
|
||||||
get() = if (isLight) LightBottomIconModifier else DarkBottomIconModifier
|
|
||||||
|
|
||||||
val ColorScheme.chartStyle: ChartStyle
|
val ColorScheme.chartStyle: ChartStyle
|
||||||
get() {
|
get() {
|
||||||
val defaultColors = if (isLight) DefaultColors.Light else DefaultColors.Dark
|
val defaultColors = if (isLight) DefaultColors.Light else DefaultColors.Dark
|
||||||
|
|||||||
Reference in New Issue
Block a user