Skip to content

Commit

Permalink
Playback 2023 - Top listened categories story (#1482)
Browse files Browse the repository at this point in the history
  • Loading branch information
ashiagr authored Oct 30, 2023
1 parent eefe46b commit 5dac510
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
Expand All @@ -20,8 +22,11 @@ import au.com.shiftyjelly.pocketcasts.utils.extensions.pxToDp
@Composable
fun StoryBlurredBackground(
offset: Offset,
rotate: Float = 0f,
) {
Box(Modifier.wrapContentWidth(unbounded = true)) {
Box(
Modifier.wrapContentWidth(unbounded = true)
) {
val context = LocalContext.current
val screenWidthInPx = LocalView.current.width
val screenWidthInDp = screenWidthInPx.pxToDp(context)
Expand All @@ -32,12 +37,14 @@ fun StoryBlurredBackground(
x = offset.x.toInt().pxToDp(context).dp,
y = offset.y.toInt().pxToDp(context).dp
)
.rotate(rotate)
) {
Image(
painterResource(id = R.drawable.story_blurred_background),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
.alpha(0.6f)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package au.com.shiftyjelly.pocketcasts.endofyear.utils

import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
Expand Down Expand Up @@ -37,6 +39,27 @@ fun Modifier.dynamicBackground(
drawContent()
}

fun Modifier.textGradient() =
graphicsLayer { alpha = 0.99f }
.drawWithCache {
val brush = Brush.linearGradient(
0.00f to Color(red = 0.25f, green = 0.11f, blue = 0.92f),
0.24f to Color(red = 0.68f, green = 0.89f, blue = 0.86f),
0.50f to Color(red = 0.87f, green = 0.91f, blue = 0.53f),
0.74f to Color(red = 0.91f, green = 0.35f, blue = 0.26f),
1.00f to Color(red = 0.1f, green = 0.1f, blue = 0.1f),
start = Offset(-0.3f * size.width, -0.27f * size.height),
end = Offset(1.5f * size.width, 1.19f * size.height),
)
onDrawWithContent {
drawContent()
drawRect(
brush = brush,
blendMode = BlendMode.SrcAtop
)
}
}

enum class FadeDirection {
TopToBottom,
BottomToTop
Expand Down
Original file line number Diff line number Diff line change
@@ -1,123 +1,219 @@
package au.com.shiftyjelly.pocketcasts.endofyear.views.stories

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import au.com.shiftyjelly.pocketcasts.compose.components.TextH10
import au.com.shiftyjelly.pocketcasts.compose.components.TextH30
import au.com.shiftyjelly.pocketcasts.endofyear.components.CategoryPillar
import au.com.shiftyjelly.pocketcasts.compose.components.TextH50
import au.com.shiftyjelly.pocketcasts.compose.theme
import au.com.shiftyjelly.pocketcasts.endofyear.components.StoryBlurredBackground
import au.com.shiftyjelly.pocketcasts.endofyear.components.StoryPrimaryText
import au.com.shiftyjelly.pocketcasts.endofyear.components.StorySecondaryText
import au.com.shiftyjelly.pocketcasts.endofyear.components.disableScale
import au.com.shiftyjelly.pocketcasts.endofyear.utils.dynamicBackground
import au.com.shiftyjelly.pocketcasts.endofyear.utils.textGradient
import au.com.shiftyjelly.pocketcasts.localization.helper.tryToLocalise
import au.com.shiftyjelly.pocketcasts.models.db.helper.ListenedCategory
import au.com.shiftyjelly.pocketcasts.repositories.endofyear.stories.StoryTopListenedCategories
import au.com.shiftyjelly.pocketcasts.settings.stats.StatsHelper
import kotlin.math.min
import au.com.shiftyjelly.pocketcasts.localization.R as LR
import au.com.shiftyjelly.pocketcasts.ui.R as UR

private const val BackgroundColor = 0xFF744F9D
private val CategoryColor = Color(0xFF686C74)
private val CategoryFontSize = 40.sp
private val DefaultFontFamily = FontFamily(listOf(Font(UR.font.dm_sans)))

@Composable
fun StoryTopListenedCategoriesView(
story: StoryTopListenedCategories,
modifier: Modifier = Modifier,
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.fillMaxSize()
.dynamicBackground(Color(BackgroundColor))
.verticalScroll(rememberScrollState())
) {
Spacer(modifier = modifier.height(40.dp))
Box {
StoryBlurredBackground(
offset = Offset(
-LocalView.current.width * 0.4f,
-LocalView.current.height * 0.4f
),
rotate = 110f,
)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 40.dp)
) {
Spacer(modifier = modifier.weight(0.2f))

PrimaryText(story)

Spacer(modifier = modifier.weight(1f))
Spacer(modifier = modifier.height(14.dp))

Title(story)
SecondaryText(story)

Spacer(modifier = modifier.weight(0.5f))
Spacer(modifier = modifier.weight(0.2f))

CategoryPillars(story, modifier)
CategoryList(story, modifier)

Spacer(modifier = modifier.weight(1f))
Spacer(modifier = modifier.weight(0.5f))
}
}
}

@Composable
private fun Title(
private fun PrimaryText(
story: StoryTopListenedCategories,
modifier: Modifier = Modifier,
) {
val text = stringResource(LR.string.end_of_year_story_top_categories)
TextH30(
text = text,
textAlign = TextAlign.Center,
color = story.tintColor,
disableScale = disableScale(),
modifier = modifier
.padding(horizontal = 40.dp)
.fillMaxWidth()
val context = LocalContext.current
val text = stringResource(
LR.string.end_of_year_story_top_categories_title,
story.listenedCategories[0].simplifiedCategoryName().tryToLocalise(context.resources)
)
StoryPrimaryText(text = text, color = story.tintColor, modifier = modifier)
}

@Composable
private fun CategoryPillars(
private fun SecondaryText(
story: StoryTopListenedCategories,
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val timeText = StatsHelper.secondsToFriendlyString(
story.listenedCategories[0].totalPlayedTime,
context.resources
)
val text = stringResource(
id = LR.string.end_of_year_story_top_categories_subtitle,
story.listenedCategories[0].numberOfEpisodes,
timeText
)
StorySecondaryText(text = text, color = story.subtitleColor, modifier = modifier)
}

@Composable
private fun CategoryList(
story: StoryTopListenedCategories,
modifier: Modifier = Modifier,
) {
(0..min(story.listenedCategories.size, 3)).forEach { index ->
val listenedCategory = story.listenedCategories.atIndex(index)
listenedCategory?.let {
CategoryItem(
listenedCategory = it,
position = index,
subtitleColor = story.subtitleColor,
modifier = modifier
)
}
}
}

@Composable
fun CategoryItem(
listenedCategory: ListenedCategory,
position: Int,
subtitleColor: Color,
modifier: Modifier = Modifier,
) {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.Bottom,
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 40.dp)
) {
listOf(1, 0, 2).forEach { index ->
Spacer(modifier.weight(1f))

val listenedCategory = story.listenedCategories.atIndex(index)
listenedCategory?.let {
val timeText =
StatsHelper.secondsToFriendlyString(
listenedCategory.totalPlayedTime,
context.resources
)
CategoryPillar(
title = listenedCategory.category,
duration = timeText,
text = (index + 1).toString(),
height = (200 - index * 55).dp,
modifier = modifier
.padding(
bottom = if (index == 0) 70.dp else 0.dp,
)
TextH30(
text = "${position + 1}",
color = subtitleColor,
fontWeight = FontWeight.W700,
fontFamily = DefaultFontFamily,
disableScale = disableScale(),
modifier = modifier
.padding(end = 14.dp)
.widthIn(min = 16.dp)
)
Row(
modifier = modifier
.padding(vertical = 10.dp)
.weight(1f),
verticalAlignment = Alignment.CenterVertically
) {
if (position == 0) {
CategoryTexts(
listenedCategory = listenedCategory,
subtitleColor = Color.White,
modifier = Modifier
.textGradient()
)
} ?: CategoryPillar(
title = "",
duration = "",
text = "",
height = 200.dp,
modifier = modifier.alpha(0f)
)

Spacer(modifier.weight(1f))
} else {
CategoryTexts(
listenedCategory = listenedCategory,
titleColor = CategoryColor,
subtitleColor = subtitleColor,
modifier = Modifier
)
}
}
}
}

@Composable
private fun CategoryTexts(
listenedCategory: ListenedCategory,
titleColor: Color = MaterialTheme.theme.colors.primaryText01,
subtitleColor: Color,
modifier: Modifier,
) {
val context = LocalContext.current
val timeText = StatsHelper.secondsToFriendlyString(
listenedCategory.totalPlayedTime,
context.resources
)
Column {
TextH10(
text = listenedCategory.simplifiedCategoryName(),
maxLines = 1,
color = titleColor,
fontSize = CategoryFontSize,
fontFamily = DefaultFontFamily,
fontWeight = FontWeight.W500,
disableScale = true,
modifier = modifier,
)
Spacer(modifier = Modifier.height(3.dp))
TextH50(
text = timeText,
color = subtitleColor,
maxLines = 1,
fontFamily = DefaultFontFamily,
fontWeight = FontWeight.W600,
disableScale = disableScale(),
)
}
}

private fun List<ListenedCategory>.atIndex(index: Int) =
if (index < size) this[index] else null
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ private fun PrimaryText(
modifier: Modifier = Modifier,
) {
val text = stringResource(
id = R.string.end_of_year_story_top_podcast,
id = R.string.end_of_year_story_top_podcast_title,
story.topPodcast.title
)
StoryPrimaryText(text = text, color = story.tintColor, modifier = modifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ object LocaliseHelper {
"fiction" to R.string.discover_category_fiction,
"government" to R.string.discover_category_government,
"health & fitness" to R.string.discover_category_health,
"health" to R.string.discover_category_health_abbreviation,
"history" to R.string.discover_category_history,
"kids & family" to R.string.discover_category_kids,
"family" to R.string.discover_category_kids_abbreviation,
"leisure" to R.string.discover_category_leisure,
"music" to R.string.discover_category_music,
"news" to R.string.discover_category_news,
"religion & spirituality" to R.string.discover_category_religion,
"spirituality" to R.string.discover_category_religion_abbreviation,
"science" to R.string.discover_category_science,
"society & culture" to R.string.discover_category_society,
"culture" to R.string.discover_category_society_abbreviation,
"sports" to R.string.discover_category_sports,
"technology" to R.string.discover_category_technology,
"true crime" to R.string.discover_category_crime,
Expand Down
Loading

0 comments on commit 5dac510

Please sign in to comment.