Skip to content

Commit

Permalink
Add Winback Offer UI (#3434)
Browse files Browse the repository at this point in the history
  • Loading branch information
MiSikora authored Jan 15, 2025
1 parent f3be0c2 commit 8ef0f8a
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ private fun OnboardingImportFromPreview(
AppThemeWithBackground(themeType = themeType) {
OnboardingImportFrom(
theme = themeType,
drawableRes = IR.drawable.castbox,
drawableRes = IR.drawable.ic_heart,
title = "Import from something",
text = "Some text to go with the title.",
steps = listOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,51 @@
package au.com.shiftyjelly.pocketcasts.profile.winback

import androidx.compose.foundation.background
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
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.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import au.com.shiftyjelly.pocketcasts.compose.AppThemeWithBackground
import au.com.shiftyjelly.pocketcasts.compose.Devices
import au.com.shiftyjelly.pocketcasts.compose.components.TextH30
import au.com.shiftyjelly.pocketcasts.compose.components.TextH40
import au.com.shiftyjelly.pocketcasts.compose.components.TextH60
import au.com.shiftyjelly.pocketcasts.compose.preview.ThemePreviewParameterProvider
import au.com.shiftyjelly.pocketcasts.compose.theme
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import androidx.compose.material.Divider as MaterialDivider
import au.com.shiftyjelly.pocketcasts.images.R as IR
import au.com.shiftyjelly.pocketcasts.localization.R as LR

@Composable
internal fun WinbackOfferPage(
Expand All @@ -29,74 +59,241 @@ internal fun WinbackOfferPage(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier
.fillMaxSize()
.background(Color(0xFFEED7D8))
.padding(16.dp),
.nestedScroll(rememberNestedScrollInteropConnection())
.verticalScroll(rememberScrollState()),
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.height(80.dp)
.fillMaxWidth(),
) {
Text(
text = "Winback Offer",
color = Color.Black,
)
}
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.height(64.dp)
.fillMaxWidth()
.background(Color(0xFFD6B7B1))
.clickable(onClick = onClaimOffer),
) {
Text(
text = "Claim Offer",
color = Color.Black,
)
}
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.height(64.dp)
.fillMaxWidth()
.background(Color(0xFFAE8094))
.clickable(onClick = onSeeAvailablePlans),
) {
Text(
text = "See Plans",
color = Color.Black,
)
}
Box(
contentAlignment = Alignment.Center,
Spacer(
modifier = Modifier.height(24.dp),
)
WinbackOfferHeader(
modifier = Modifier
.height(64.dp)
.fillMaxWidth()
.background(Color(0xFF85506E))
.clickable(onClick = onSeeHelpAndFeedback),
) {
Text(
text = "Help & Feedback",
color = Color.White,
)
}
.padding(horizontal = 32.dp),
)
Spacer(
modifier = Modifier.height(16.dp),
)
ClaimFreeOffer(
onClick = onClaimOffer,
modifier = Modifier.fillMaxWidth(),
)
Divider()
AvailablePlans(
onClick = onSeeAvailablePlans,
modifier = Modifier.fillMaxWidth(),
)
Divider()
HelpAndFeedback(
onClick = onSeeHelpAndFeedback,
modifier = Modifier.fillMaxWidth(),
)
Divider()
Spacer(
modifier = Modifier.weight(1f),
)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.height(64.dp)
.fillMaxWidth()
.background(Color(0xFF58443E))
.clickable(onClick = onContinueToCancellation),
) {
Text(
text = "Cancel",
color = Color.White,
ContinueToCancellation(
onClick = onContinueToCancellation,
modifier = Modifier.align(Alignment.CenterHorizontally),
)
Spacer(
modifier = Modifier.height(52.dp),
)
}
}

@Composable
private fun WinbackOfferHeader(
modifier: Modifier = Modifier,
) {
Text(
text = stringResource(LR.string.winback_offer_header),
fontWeight = FontWeight.Bold,
fontSize = 28.sp,
lineHeight = 38.5.sp,
color = MaterialTheme.theme.colors.primaryText01,
textAlign = TextAlign.Center,
modifier = modifier,
)
}

@Composable
private fun ClaimFreeOffer(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
RowWithIcon(
icon = painterResource(IR.drawable.ic_heart_2),
modifier = modifier
.clickable(onClick = onClick)
.semantics(mergeDescendants = true) { role = Role.Button }
.padding(horizontal = 16.dp, vertical = 24.dp),
) {
Column {
TextH40(
text = stringResource(LR.string.winback_offer_free_offer_title),
)
Spacer(
modifier = Modifier.height(4.dp),
)
TextH60(
text = stringResource(LR.string.winback_offer_free_offer_description, "\$3.99"),
color = MaterialTheme.theme.colors.primaryText02,
)
Spacer(
modifier = Modifier.height(12.dp),
)
Button(
onClick = onClick,
shape = RoundedCornerShape(8.dp),
modifier = Modifier
.fillMaxWidth()
.padding(end = 12.dp),
) {
Text(
text = stringResource(LR.string.winback_offer_free_offer_button_label),
fontSize = 13.sp,
lineHeight = 15.5.sp,
letterSpacing = 1.sp,
)
}
}
}
}

@Composable
private fun AvailablePlans(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
RowWithIcon(
icon = painterResource(IR.drawable.ic_different_plan),
modifier = modifier
.clickable(onClick = onClick, role = Role.Button)
.padding(horizontal = 16.dp, vertical = 24.dp),
) {
ChevronRow {
Column {
TextH40(
text = stringResource(LR.string.winback_offer_differnt_plan_title),
)
Spacer(
modifier = Modifier.height(4.dp),
)
TextH60(
text = stringResource(LR.string.winback_offer_differnt_plan_description),
color = MaterialTheme.theme.colors.primaryText02,
)
}
}
}
}

@Composable
private fun HelpAndFeedback(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
RowWithIcon(
icon = painterResource(IR.drawable.ic_help),
modifier = modifier
.clickable(onClick = onClick, role = Role.Button)
.padding(horizontal = 16.dp, vertical = 24.dp),
) {
ChevronRow {
Column {
TextH40(
text = stringResource(LR.string.winback_offer_help_title),
)
Spacer(
modifier = Modifier.height(4.dp),
)
TextH60(
text = stringResource(LR.string.winback_offer_help_description),
color = MaterialTheme.theme.colors.primaryText02,
)
}
}
}
}

@Composable
private fun ContinueToCancellation(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Box(
modifier = modifier
.clickable(onClick = onClick)
.semantics(mergeDescendants = true) { role = Role.Button },
) {
TextH30(
text = stringResource(LR.string.winback_offer_cancel_continue_button_label),
textAlign = TextAlign.Center,
modifier = Modifier.padding(16.dp),
)
}
}

@Composable
private fun RowWithIcon(
icon: Painter,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = modifier,
) {
Image(
painter = icon,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.theme.colors.primaryIcon01),
)
content()
}
}

@Composable
private fun ChevronRow(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = modifier,
) {
content()
Image(
painter = painterResource(IR.drawable.ic_chevron_small_right),
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.theme.colors.primaryIcon02),
)
}
}

@Composable
private fun Divider(
modifier: Modifier = Modifier,
) {
MaterialDivider(
color = MaterialTheme.theme.colors.primaryUi05,
startIndent = 16.dp,
modifier = modifier,
)
}

@Preview(device = Devices.PortraitRegular)
@Composable
private fun WinbackOfferPagePreview(
@PreviewParameter(ThemePreviewParameterProvider::class) theme: Theme.ThemeType,
) {
AppThemeWithBackground(theme) {
WinbackOfferPage(
onClaimOffer = {},
onSeeAvailablePlans = {},
onSeeHelpAndFeedback = {},
onContinueToCancellation = {},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF00FF"
android:pathData="M9.793,7.293C10.183,6.902 10.817,6.902 11.207,7.293L15.914,12L11.207,16.707C10.817,17.098 10.183,17.098 9.793,16.707C9.402,16.317 9.402,15.683 9.793,15.293L13.086,12L9.793,8.707C9.402,8.317 9.402,7.683 9.793,7.293Z" />
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF00FF"
android:pathData="M12.621,2.793C13.012,3.183 13.012,3.817 12.621,4.207L10.828,6H12C16.418,6 20,9.582 20,14C20,18.418 16.418,22 12,22C7.582,22 4,18.418 4,14C4,13.448 4.448,13 5,13C5.552,13 6,13.448 6,14C6,17.314 8.686,20 12,20C15.314,20 18,17.314 18,14C18,10.686 15.314,8 12,8H10.828L12.621,9.793C13.012,10.183 13.012,10.817 12.621,11.207C12.231,11.598 11.598,11.598 11.207,11.207L7,7L11.207,2.793C11.598,2.402 12.231,2.402 12.621,2.793Z" />
</vector>
9 changes: 9 additions & 0 deletions modules/services/images/src/main/res/drawable/ic_heart_2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF00FF"
android:pathData="M3,10.5C3,7.118 5.822,4.5 9.148,4.5C10.301,4.5 11.269,4.938 12,5.457C12.731,4.938 13.699,4.5 14.852,4.5C18.178,4.5 21,7.118 21,10.5C21,11.792 20.504,12.966 19.915,13.922C19.317,14.892 18.536,15.78 17.758,16.543C16.202,18.069 14.457,19.285 13.609,19.845C12.63,20.49 11.37,20.49 10.391,19.845C9.543,19.285 7.798,18.069 6.242,16.543C5.464,15.78 4.683,14.892 4.085,13.922C3.496,12.966 3,11.792 3,10.5ZM11.492,18.175C11.803,18.38 12.197,18.38 12.508,18.175C14.118,17.113 19,13.635 19,10.5C19,8.291 17.143,6.5 14.852,6.5C13.907,6.5 13.091,7.048 12.552,7.611C12.278,7.898 11.722,7.898 11.448,7.611C10.909,7.048 10.093,6.5 9.148,6.5C6.857,6.5 5,8.291 5,10.5C5,13.635 9.882,17.113 11.492,18.175Z" />
</vector>
Loading

0 comments on commit 8ef0f8a

Please sign in to comment.