Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polish legend cards #294

Merged
merged 4 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ fun UniversalAvatarThumbnail(
borderSizeOverride: Dp? = null,
backgroundColor: Color = AppTheme.extraColorScheme.surfaceVariantAlt1,
onClick: (() -> Unit)? = null,
hasInnerBorderOverride: Boolean = true,
defaultAvatar: @Composable () -> Unit = { DefaultAvatarThumbnailPlaceholderListItemImage() },
) {
val hasLegendBorder = legendaryCustomization?.avatarGlow == true &&
legendaryCustomization.legendaryStyle != LegendaryStyle.NO_CUSTOMIZATION

val borderBrush = if (hasLegendBorder) {
legendaryCustomization?.legendaryStyle?.primaryBrush
legendaryCustomization.legendaryStyle?.primaryBrush
} else {
null
}
Expand All @@ -65,7 +66,7 @@ fun UniversalAvatarThumbnail(
cdnVariantUrl = variant?.mediaUrl,
sourceUrl = avatarCdnImage?.sourceUrl,
hasOuterBorder = hasBorder && avatarSize > 0.dp,
hasInnerBorder = hasLegendBorder && avatarSize > 0.dp,
hasInnerBorder = hasLegendBorder && avatarSize > 0.dp && hasInnerBorderOverride,
borderBrush = borderBrush ?: Brush.linearGradient(
colors = listOf(
fallbackBorderColor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.DropdownMenu
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.PopupProperties
Expand All @@ -16,12 +17,13 @@ fun DropdownPrimalMenu(
onDismissRequest: () -> Unit,
offset: DpOffset = DpOffset(0.dp, 0.dp),
properties: PopupProperties = PopupProperties(focusable = true),
backgroundColor: Color = AppTheme.extraColorScheme.surfaceVariantAlt1,
content: @Composable ColumnScope.() -> Unit,
) {
DropdownMenu(
modifier = Modifier
.background(
color = AppTheme.extraColorScheme.surfaceVariantAlt1,
color = backgroundColor,
shape = AppTheme.shapes.small,
),
expanded = expanded,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
Expand All @@ -30,6 +32,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
Expand All @@ -50,6 +53,7 @@ import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.rotate
Expand All @@ -76,11 +80,17 @@ import net.primal.android.core.utils.formatToDefaultDateFormat
import net.primal.android.premium.legend.domain.LegendaryCustomization
import net.primal.android.premium.legend.domain.LegendaryStyle
import net.primal.android.profile.details.ui.ProfilePremiumBadge
import net.primal.android.profile.details.ui.model.PremiumProfileDataUi
import net.primal.android.profile.details.ui.model.shouldShowPremiumBadge
import net.primal.android.theme.AppTheme

private val TOP_ICON_COLOR = Color(0xFF1E1E1E)
private val GLOW_RECT_COLOR = Color(0xFFCCCCCC)
private val CARD_BACKGROUND_COLOR = Color(0xFF222222)
private val DROPDOWN_BACKGROUND_COLOR = Color(0xFF282828)
private val PRIMARY_TEXT_COLOR = Color(0xFFFFFFFF)
private val SECONDARY_TEXT_COLOR = Color(0xFFAAAAAA)
private val FALLBACK_BACKGROUND_ELEMENT_COLOR = Color(0xFF444444)

private const val PRIMAL_2_0_RELEASE_DATE_IN_SECONDS = 1732147200L

Expand Down Expand Up @@ -126,18 +136,21 @@ fun LegendCardScreen(
.padding(20.dp)
.fillMaxWidth()
.clip(AppTheme.shapes.medium)
.background(AppTheme.extraColorScheme.surfaceVariantAlt1)
.background(CARD_BACKGROUND_COLOR)
.drawAnimatedBackgroundAndGlow(
brush = state.profile?.premiumDetails?.legendaryCustomization?.legendaryStyle?.secondaryBrush,
brush = state.profile?.premiumDetails?.legendaryCustomization?.legendaryStyle?.secondaryBrush
?: SolidColor(FALLBACK_BACKGROUND_ELEMENT_COLOR),
backgroundProgress = animationProgress,
glowProgress = glowProgress,
)
.padding(bottom = 16.dp)
.padding(4.dp),
.padding(4.dp)
.aspectRatio(ratio = 0.56f),
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(28.dp, Alignment.CenterVertically),
verticalArrangement = Arrangement.SpaceBetween,
) {
if (state.isActiveAccountCard) {
OptionsDropdownMenu(
Expand Down Expand Up @@ -178,17 +191,15 @@ private suspend fun AnimationState<Float, AnimationVector1D>.startAnimation(dela
)

private fun Modifier.drawAnimatedBackgroundAndGlow(
brush: Brush?,
brush: Brush,
backgroundProgress: AnimationState<Float, AnimationVector1D>,
glowProgress: AnimationState<Float, AnimationVector1D>,
) = drawWithContent {
val (topStart, bottomStart, topEnd) = makeEdgePaths(animationProgress = backgroundProgress)

brush?.let {
drawPath(alpha = 0.25f, path = topStart, brush = brush)
drawPath(alpha = 0.25f, path = bottomStart, brush = brush)
drawPath(path = topEnd, brush = brush)
}
drawPath(alpha = 0.25f, path = topStart, brush = brush)
drawPath(alpha = 0.15f, path = bottomStart, brush = brush)
drawPath(path = topEnd, brush = brush)

drawContent()
drawGlowRectangle(glowProgress = glowProgress)
Expand Down Expand Up @@ -256,7 +267,7 @@ private fun ButtonsColumn(
private fun ContentDrawScope.drawGlowRectangle(glowProgress: AnimationState<Float, AnimationVector1D>) =
rotate(degrees = 45f) {
drawRect(
topLeft = Offset(x = -440f, y = 1740f - glowProgress.value * 2180f),
topLeft = Offset(x = -440f, y = 1840f - glowProgress.value * 2280f),
alpha = .05f + glowProgress.value * .25f,
color = GLOW_RECT_COLOR,
size = Size(width = 2000f, height = 300f),
Expand All @@ -268,26 +279,26 @@ private fun DrawScope.makeEdgePaths(
animationProgress: AnimationState<Float, AnimationVector1D>,
): Triple<Path, Path, Path> {
val topStart = Path().apply {
moveTo(0f, animationProgress.value * size.height * 0.30f)
lineTo(animationProgress.value * size.height * 0.30f, 0f)
moveTo(0f, animationProgress.value * size.height * .31f)
lineTo(animationProgress.value * size.width * .6f, 0f)
lineTo(-10f, 0f)
close()
}

val bottomStart = Path().apply {
moveTo(
x = 0f,
y = size.height * 0.70f + (1 - animationProgress.value) * size.height * .3f,
y = size.height * 0.745f + (1 - animationProgress.value) * size.height * .255f,
)
lineTo(0f, size.height)
lineTo(animationProgress.value * size.height * 0.30f, size.height)
lineTo(animationProgress.value * size.width * 0.49f, size.height)
close()
}

val topEnd = Path().apply {
moveTo(size.width - 10f - animationProgress.value * size.width, 0f)
lineTo(size.width, 0f)
lineTo(size.width, animationProgress.value * size.height * .45f)
lineTo(size.width, animationProgress.value * size.height * .5f)
close()
}

Expand All @@ -305,11 +316,11 @@ private fun LegendaryStyle?.resolveNoCustomizationAndNull(): Color =

private fun LegendaryStyle?.resolveButtonColor(): Color =
when (this) {
LegendaryStyle.NO_CUSTOMIZATION, LegendaryStyle.GOLD, LegendaryStyle.AQUA,
LegendaryStyle.GOLD, LegendaryStyle.AQUA,
LegendaryStyle.SILVER, LegendaryStyle.TEAL, LegendaryStyle.BROWN, null,
-> Color.Black

LegendaryStyle.PURPLE, LegendaryStyle.PURPLE_HAZE,
LegendaryStyle.NO_CUSTOMIZATION, LegendaryStyle.PURPLE, LegendaryStyle.PURPLE_HAZE,
LegendaryStyle.BLUE, LegendaryStyle.SUN_FIRE,
-> Color.White
}
Expand All @@ -328,22 +339,24 @@ private fun LegendDescription(modifier: Modifier = Modifier, profile: ProfileDet
enter = makeEnterTransition(delayMillis = 583),
) {
Column(
modifier = modifier.fillMaxWidth(),
modifier = modifier
.padding(horizontal = 20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterVertically),
) {
Text(
text = stringResource(id = R.string.premium_legend_card_legend_since) + " " +
legendSince.formatToDefaultDateFormat(FormatStyle.LONG),
style = AppTheme.typography.bodyMedium,
color = AppTheme.colorScheme.onPrimary,
color = PRIMARY_TEXT_COLOR,
fontSize = 15.sp,
fontWeight = FontWeight.SemiBold,
)
Text(
text = profile.premiumDetails?.legendaryCustomization?.currentShoutout ?: "",
style = AppTheme.typography.bodyMedium,
color = AppTheme.extraColorScheme.onSurfaceVariantAlt2,
color = SECONDARY_TEXT_COLOR,
fontSize = 14.sp,
textAlign = TextAlign.Center,
)
Expand Down Expand Up @@ -388,51 +401,65 @@ private fun ProfileSummary(modifier: Modifier = Modifier, profile: ProfileDetail
verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterVertically),
) {
Box(
modifier = Modifier.size(100.dp),
modifier = Modifier.size(145.dp),
contentAlignment = Alignment.Center,
) {
UniversalAvatarThumbnail(
modifier = Modifier
.alpha(avatarSizeAndAlphaProgress.value)
.rotate(avatarRotation.value),
avatarSize = (avatarSizeAndAlphaProgress.value * 100).dp,
avatarSize = (avatarSizeAndAlphaProgress.value * 145).dp,
avatarCdnImage = profile.avatarCdnImage,
legendaryCustomization = profile.premiumDetails?.legendaryCustomization,
hasInnerBorderOverride = false,
)
}
Spacer(modifier = Modifier.height(10.dp))
AnimatedDisplayName(showContent = showContent, profile = profile)

profile.internetIdentifier?.let { internetIdentifier ->
AnimatedVisibility(
visible = showContent,
enter = makeEnterTransition(delayMillis = 416),
) {
Text(
modifier = Modifier,
text = internetIdentifier.formatNip05Identifier(),
style = AppTheme.typography.bodyMedium.copy(
lineHeight = 12.sp,
),
color = AppTheme.colorScheme.onPrimary,
)
}
AnimatedInternetIdentifier(showContent = showContent, internetIdentifier = internetIdentifier)
}

if (profile.premiumDetails?.shouldShowPremiumBadge() == true) {
AnimatedVisibility(
visible = showContent,
enter = makeEnterTransition(delayMillis = 500),
) {
ProfilePremiumBadge(
firstCohort = profile.premiumDetails.cohort1 ?: "",
secondCohort = profile.premiumDetails.cohort2 ?: "",
legendaryStyle = profile.premiumDetails.legendaryCustomization?.legendaryStyle,
)
}
AnimatedPremiumBadge(showContent = showContent, premiumDetails = profile.premiumDetails)
}
}
}

@Composable
private fun ColumnScope.AnimatedPremiumBadge(showContent: Boolean, premiumDetails: PremiumProfileDataUi) {
AnimatedVisibility(
visible = showContent,
enter = makeEnterTransition(delayMillis = 500),
) {
ProfilePremiumBadge(
firstCohort = premiumDetails.cohort1 ?: "",
secondCohort = premiumDetails.cohort2 ?: "",
legendaryStyle = premiumDetails.legendaryCustomization?.legendaryStyle,
firstCohortFontSize = 14.sp,
secondCohortFontSize = 14.sp,
)
}
}

@Composable
private fun ColumnScope.AnimatedInternetIdentifier(showContent: Boolean, internetIdentifier: String) {
AnimatedVisibility(
visible = showContent,
enter = makeEnterTransition(delayMillis = 416),
) {
Text(
modifier = Modifier,
text = internetIdentifier.formatNip05Identifier(),
style = AppTheme.typography.bodyMedium.copy(
lineHeight = 12.sp,
),
color = PRIMARY_TEXT_COLOR,
)
}
}

@Composable
private fun ColumnScope.AnimatedDisplayName(showContent: Boolean, profile: ProfileDetailsUi) {
AnimatedVisibility(
Expand All @@ -442,6 +469,7 @@ private fun ColumnScope.AnimatedDisplayName(showContent: Boolean, profile: Profi
Box {
NostrUserText(
displayName = profile.authorDisplayName,
displayNameColor = PRIMARY_TEXT_COLOR,
internetIdentifier = profile.internetIdentifier,
internetIdentifierBadgeSize = 26.dp,
internetIdentifierBadgeAlign = PlaceholderVerticalAlign.Center,
Expand Down Expand Up @@ -479,6 +507,7 @@ private fun OptionsDropdownMenu(
onLegendSettingsClick: () -> Unit,
) {
var menuVisible by remember { mutableStateOf(false) }
val itemColors = MenuDefaults.itemColors(textColor = PRIMARY_TEXT_COLOR, trailingIconColor = PRIMARY_TEXT_COLOR)
Box(
modifier = modifier
.fillMaxWidth()
Expand All @@ -496,16 +525,19 @@ private fun OptionsDropdownMenu(
DropdownPrimalMenu(
expanded = menuVisible,
onDismissRequest = { menuVisible = false },
backgroundColor = DROPDOWN_BACKGROUND_COLOR,
) {
DropdownPrimalMenuItem(
trailingIconVector = Icons.Default.Close,
text = stringResource(id = R.string.premium_legend_card_dropdown_close),
onClick = onBackClick,
colors = itemColors,
)
DropdownPrimalMenuItem(
trailingIconVector = PrimalIcons.Settings,
text = stringResource(id = R.string.premium_legend_card_dropdown_legend_settings),
onClick = onLegendSettingsClick,
colors = itemColors,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fun PrimalLegendProfile.asLegendaryCustomization() =
LegendaryCustomization(
avatarGlow = avatarGlow,
customBadge = customBadge,
legendaryStyle = LegendaryStyle.valueById(id = styleId),
legendaryStyle = LegendaryStyle.valueById(id = styleId ?: ""),
legendSince = legendSince,
currentShoutout = currentShoutout,
inLeaderboard = inLeaderboard,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package net.primal.android.premium.legend.domain
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor

@Suppress("MagicNumber")
enum class LegendaryStyle(
Expand All @@ -17,9 +18,7 @@ enum class LegendaryStyle(
primaryBrush = Brush.linearGradient(
listOf(Color.Transparent, Color.Transparent),
),
secondaryBrush = Brush.linearGradient(
listOf(Color.Transparent, Color.Transparent),
),
secondaryBrush = SolidColor(Color(0xFF444444)),
),
GOLD(
id = "GOLD",
Expand Down
Loading