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

Playback 2023 - Improvements #1524

Merged
merged 17 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from 15 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 @@ -3,6 +3,7 @@ package au.com.shiftyjelly.pocketcasts.endofyear
import android.content.Context
import au.com.shiftyjelly.pocketcasts.preferences.Settings
import au.com.shiftyjelly.pocketcasts.repositories.endofyear.stories.Story
import au.com.shiftyjelly.pocketcasts.repositories.endofyear.stories.StoryCompletionRate
import au.com.shiftyjelly.pocketcasts.repositories.endofyear.stories.StoryListenedCategories
import au.com.shiftyjelly.pocketcasts.repositories.endofyear.stories.StoryListenedNumbers
import au.com.shiftyjelly.pocketcasts.repositories.endofyear.stories.StoryListeningTime
Expand All @@ -25,7 +26,7 @@ class ShareableTextProvider @Inject constructor(
) {
var chosenActivity: String? = null
private var shortURL: String = Settings.SERVER_SHORT_URL
private val hashtags = listOf("pocketcasts", "endofyear2023").joinToString(" ") { "#$it" }
private val hashtags = listOf("pocketcasts", "playback2023").joinToString(" ") { "#$it" }

suspend fun getShareableDataForStory(
story: Story,
Expand Down Expand Up @@ -123,6 +124,10 @@ class ShareableTextProvider @Inject constructor(
)
}

is StoryCompletionRate -> {
resources.getString(LR.string.end_of_year_stories_completion_rate_share_text)
}

else -> ""
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fun StoriesPage(
Box(modifier = modifier.size(dialogSize)) {
when (state) {
is State.Loaded -> {
viewModel.trackStoryShown()
viewModel.trackStoryOrUpsellShown()
StoriesView(
state = state as State.Loaded,
progress = viewModel.progress,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class StoriesViewModel @Inject constructor(

private val currentStoryIsPlus: Boolean
get() = stories.value[currentIndex].plusOnly
private var currentUserTier: UserTier = UserTier.Free
private var manuallySkipped = false

init {
Expand All @@ -81,12 +82,17 @@ class StoriesViewModel @Inject constructor(
val onProgressChanged: (Float) -> Unit = { progress ->
mutableState.value = State.Loading(progress)
}
endOfYearManager.downloadListeningHistory(onProgressChanged = onProgressChanged)
stories.value = endOfYearManager.loadStories()
combine(
subscriptionManager.freeTrialForSubscriptionTierFlow(Subscription.SubscriptionTier.PLUS),
settings.cachedSubscriptionStatus.flow
) { upsellState, _ ->
currentUserTier = settings.userTier
val lastUserTier = (state.value as? State.Loaded)?.userTier
if (lastUserTier == [email protected]) return@combine

endOfYearManager.downloadListeningHistory(onProgressChanged = onProgressChanged)
stories.value = endOfYearManager.loadStories()

updateState(upsellState)
if (state.value is State.Loaded) start()
}.stateIn(this)
Expand All @@ -108,7 +114,7 @@ class StoriesViewModel @Inject constructor(
xStartOffsets = List(numOfStories) { getXStartOffsetAtIndex(it) },
widths = storyLengthsInMs.map { it / totalLengthInMs.toFloat() },
),
userTier = settings.userTier,
userTier = currentUserTier,
freeTrial = freeTrial,
)
}
Expand Down Expand Up @@ -242,7 +248,7 @@ class StoriesViewModel @Inject constructor(
}

private fun isPaidUser(): Boolean {
val currentState = state.value as State.Loaded
val currentState = state.value as? State.Loaded ?: return false
return currentState.userTier != UserTier.Free
}

Expand Down Expand Up @@ -301,11 +307,16 @@ class StoriesViewModel @Inject constructor(
object Error : State()
}

fun trackStoryShown() {
fun trackStoryOrUpsellShown() {
val currentState = state.value as State.Loaded
val currentStory = requireNotNull(currentState.currentStory)
val event = if (shouldShowUpsell()) {
AnalyticsEvent.END_OF_YEAR_UPSELL_SHOWN
} else {
AnalyticsEvent.END_OF_YEAR_STORY_SHOWN
}
analyticsTracker.track(
AnalyticsEvent.END_OF_YEAR_STORY_SHOWN,
event,
AnalyticsProp.storyShown(currentStory.identifier)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private fun UpsellButton(
hasFreeTrial = freeTrial.exists
),
onClick = onUpsellClicked,
modifier = modifier
modifier = modifier.fillMaxSize(.65f)
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package au.com.shiftyjelly.pocketcasts.endofyear.components

import androidx.compose.foundation.layout.fillMaxSize
import androidx.annotation.DrawableRes
import androidx.compose.material.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand All @@ -15,6 +15,7 @@ fun StoryButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
@DrawableRes textIcon: Int? = null,
) {
RowButton(
text = text,
Expand All @@ -23,7 +24,7 @@ fun StoryButton(
cornerRadius = 4.dp,
textColor = ButtonTextColor,
onClick = onClick,
modifier = modifier
.fillMaxSize(.65f)
modifier = modifier,
textIcon = textIcon,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package au.com.shiftyjelly.pocketcasts.endofyear.views
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.VectorDrawable
import android.view.View
import android.view.WindowManager
import androidx.appcompat.widget.LinearLayoutCompat
Expand All @@ -11,10 +12,17 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import au.com.shiftyjelly.pocketcasts.endofyear.StoriesViewAspectRatioForTablet
import au.com.shiftyjelly.pocketcasts.utils.Util
import au.com.shiftyjelly.pocketcasts.utils.extensions.deviceAspectRatio
import au.com.shiftyjelly.pocketcasts.utils.extensions.dpToPx
import au.com.shiftyjelly.pocketcasts.images.R as IR

private const val AppLogoWidthInDp = 130
private const val AppLogoHeightInDp = 26
private const val AppLogoPaddingBottomInDp = 40

/* Returns a callback to get bitmap for the passed composable.
The composable is converted to ComposeView and laid out into AndroidView otherwise an illegal state exception is thrown:
Expand Down Expand Up @@ -65,11 +73,35 @@ fun createBitmapFromView(view: View, width: Int, height: Int): Bitmap {
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)

canvas.setBitmap(bitmap)
// Draw story view
view.draw(canvas)
// Draw app logo
canvas.drawAppLogo(view.context)

return bitmap
}

private fun Canvas.drawAppLogo(
context: Context,
) {
val appLogoBitmap = (
ContextCompat
.getDrawable(context, IR.drawable.ic_logo_title_hor_light) as? VectorDrawable
)
?.toBitmap(
width = AppLogoWidthInDp.dpToPx(context),
height = AppLogoHeightInDp.dpToPx(context),
)
appLogoBitmap?.let {
drawBitmap(
it,
(this.width - appLogoBitmap.width) / 2f,
(this.height - (appLogoBitmap.height + AppLogoPaddingBottomInDp.dpToPx(context))).toFloat(),
null,
)
}
}

private fun getAspectRatioForBitmap(context: Context) =
if (Util.isTablet(context)) {
StoriesViewAspectRatioForTablet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ fun StoryCompletionRateView(
.fillMaxSize()
.background(story.backgroundColor)
.verticalScroll(rememberScrollState())
.padding(vertical = 40.dp)
.padding(vertical = 30.dp)
) {
Spacer(modifier = modifier.weight(0.2f))
Spacer(modifier = modifier.height(40.dp))

SubscriptionBadgeForTier(
tier = SubscriptionTier.fromUserTier(userTier),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,36 @@ import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import au.com.shiftyjelly.pocketcasts.compose.AppTheme
import au.com.shiftyjelly.pocketcasts.compose.components.Confetti
import au.com.shiftyjelly.pocketcasts.compose.components.TextP40
import au.com.shiftyjelly.pocketcasts.endofyear.R
import au.com.shiftyjelly.pocketcasts.endofyear.components.StoryAppLogo
import au.com.shiftyjelly.pocketcasts.endofyear.components.StoryBlurredBackground
import au.com.shiftyjelly.pocketcasts.endofyear.components.StoryBlurredBackgroundStyle
import au.com.shiftyjelly.pocketcasts.endofyear.components.StoryFontFamily
import au.com.shiftyjelly.pocketcasts.endofyear.components.StoryButton
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.repositories.endofyear.stories.StoryEpilogue
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import au.com.shiftyjelly.pocketcasts.utils.extensions.dpToPx
import au.com.shiftyjelly.pocketcasts.utils.featureflag.UserTier
import au.com.shiftyjelly.pocketcasts.images.R as IR
import au.com.shiftyjelly.pocketcasts.localization.R as LR

private val HeartImageSize = 72.dp
Expand Down Expand Up @@ -79,7 +71,7 @@ fun StoryEpilogueView(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 40.dp)
.padding(vertical = 30.dp)
) {
Spacer(modifier = modifier.weight(1f))

Expand Down Expand Up @@ -151,30 +143,12 @@ private fun ReplayButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
BoxWithConstraints(
modifier = Modifier.fillMaxWidth(0.6f),
contentAlignment = Alignment.Center
) {
Button(
onClick = { onClick() },
shape = RoundedCornerShape(4.dp),
colors = ButtonDefaults
.buttonColors(backgroundColor = Color.White),
) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = null,
tint = Color.Black
)
TextP40(
text = stringResource(id = LR.string.end_of_year_replay),
color = Color.Black,
fontFamily = StoryFontFamily,
disableScale = disableScale(),
modifier = modifier.padding(2.dp)
)
}
}
StoryButton(
text = stringResource(id = LR.string.end_of_year_replay),
onClick = onClick,
textIcon = IR.drawable.ic_retry,
modifier = modifier.width(250.dp)
)
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fun StoryListenedCategoriesView(
.fillMaxSize()
.podcastDynamicBackground(story.listenedCategories[0].toPodcast())
.verticalScroll(rememberScrollState())
.padding(vertical = 30.dp)
) {
Spacer(modifier = modifier.height(40.dp))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ fun StoryListenedNumbersView(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 40.dp)
.padding(vertical = 30.dp)
) {
Spacer(modifier = modifier.weight(0.2f))
Spacer(modifier = modifier.height(40.dp))

PrimaryText(story)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ fun StoryListeningTimeView(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 40.dp)
.padding(vertical = 30.dp)
) {
Spacer(modifier = modifier.weight(0.2f))
Spacer(modifier = modifier.height(40.dp))

PrimaryText(story, modifier)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ fun StoryLongestEpisodeView(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 40.dp)
.padding(vertical = 30.dp)
) {

Spacer(modifier = modifier.weight(0.2f))
Spacer(modifier = modifier.height(40.dp))

PrimaryText(story)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ fun StoryTopFivePodcastsView(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 40.dp)
.padding(vertical = 30.dp)
) {
Spacer(modifier = modifier.weight(0.2f))
Spacer(modifier = modifier.height(40.dp))

PrimaryText(story)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import androidx.compose.ui.res.stringResource
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.text.intl.Locale
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import au.com.shiftyjelly.pocketcasts.compose.components.TextH10
Expand Down Expand Up @@ -64,9 +65,9 @@ fun StoryTopListenedCategoriesView(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 40.dp)
.padding(vertical = 30.dp)
) {
Spacer(modifier = modifier.weight(0.2f))
Spacer(modifier = modifier.height(40.dp))

PrimaryText(story)

Expand All @@ -89,8 +90,14 @@ private fun PrimaryText(
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val language = Locale.current.language
val textResId = if (language == "en") {
LR.string.end_of_year_story_top_categories_title_english_only
} else {
LR.string.end_of_year_story_top_categories_title
}
val text = stringResource(
LR.string.end_of_year_story_top_categories_title,
textResId,
story.listenedCategories[0].simplifiedCategoryName().tryToLocalise(context.resources)
)
StoryPrimaryText(text = text, color = story.tintColor, modifier = modifier)
Expand Down
Loading