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

ALTAPPS-1303: Shared, Android mobile content trial #1111

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1cbf072
Add mobile.content_trial feature flag
XanderZhu Jul 16, 2024
befc7c9
Replace Subscription.areProblemsLimited usage with Subscription.getPr…
XanderZhu Jul 17, 2024
e64672e
Merge branch 'refs/heads/develop' into feature/ALTAPPS-1303/Shared-An…
XanderZhu Jul 17, 2024
5a2eff9
Implement FeatureValues
XanderZhu Jul 17, 2024
df610e2
Rename Subscription.areProblemsLimited to isDailyProblemsLimitReached
XanderZhu Jul 17, 2024
7dd798a
Disable limits for stepQuiz & stepQuizToolbar features
XanderZhu Jul 17, 2024
c0205e5
Disable problems limits bottom sheet
XanderZhu Jul 17, 2024
9abc6bf
Disable automatic paywall show for MobileContentTrial subscription
XanderZhu Jul 18, 2024
d370d6c
Remove redundant early profile fetch in the MainStepQuizToolbarAction…
XanderZhu Jul 18, 2024
a594e42
Revert paywall disabling
XanderZhu Jul 18, 2024
b8f4b6e
Rename ProblemsLimitType
XanderZhu Jul 18, 2024
f339309
Show paywall when all the free topics are passed
XanderZhu Jul 18, 2024
9b9a2bc
Add locked icon to the locked activities
XanderZhu Jul 19, 2024
5880eb3
Show paywall on locked activity click
XanderZhu Jul 19, 2024
114071f
Implement paywall in the study plan
XanderZhu Jul 22, 2024
c4ef0a8
Update paywall ui & texts
XanderZhu Jul 22, 2024
bee8851
Close MobileContentTrial subscription with canMakePayments flag
XanderZhu Jul 22, 2024
fab1f87
Fix ios build
XanderZhu Jul 22, 2024
8e3deeb
Fix ktlint
XanderZhu Jul 22, 2024
c8bfc99
Fix tests
XanderZhu Jul 22, 2024
0d0d68d
Self review
XanderZhu Jul 22, 2024
4e5f6be
Self review
XanderZhu Jul 22, 2024
5420716
iOS: Fix swiftlint
ivan-magda Jul 23, 2024
eb7395a
Merge remote-tracking branch 'origin/develop' into feature/ALTAPPS-13…
ivan-magda Jul 23, 2024
2f84b22
Apply review suggestions
ivan-magda Jul 23, 2024
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
@@ -1,6 +1,5 @@
package org.hyperskill.app.android.paywall.ui

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
Expand Down Expand Up @@ -31,17 +30,14 @@ import androidx.compose.ui.unit.sp
import org.hyperskill.app.R
import org.hyperskill.app.android.core.extensions.compose.plus
import org.hyperskill.app.android.core.view.ui.widget.compose.HyperskillButton
import org.hyperskill.app.android.core.view.ui.widget.compose.HyperskillButtonDefaults
import org.hyperskill.app.android.core.view.ui.widget.compose.HyperskillTheme

@Composable
fun PaywallContent(
buyButtonText: String,
priceText: String?,
isContinueWithLimitsButtonVisible: Boolean,
onTermsOfServiceClick: () -> Unit,
onBuySubscriptionClick: () -> Unit,
onContinueWithLimitsClick: () -> Unit,
modifier: Modifier = Modifier,
padding: PaddingValues = PaddingValues()
) {
Expand All @@ -58,8 +54,7 @@ fun PaywallContent(
Image(
painter = painterResource(id = org.hyperskill.app.android.R.drawable.img_paywall),
contentDescription = null,
modifier = Modifier
.align(Alignment.CenterHorizontally)
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Spacer(modifier = Modifier.height(24.dp))
Text(
Expand All @@ -81,10 +76,6 @@ fun PaywallContent(
) {
Text(text = buyButtonText)
}
Spacer(modifier = Modifier.height(8.dp))
if (isContinueWithLimitsButtonVisible) {
ContinueButton(onClick = onContinueWithLimitsClick)
}
Spacer(modifier = Modifier.height(20.dp))
TermsOfService(
modifier = Modifier
Expand Down Expand Up @@ -116,24 +107,6 @@ private fun SubscriptionPrice(
}
}

@Composable
private fun ContinueButton(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
HyperskillButton(
onClick = onClick,
colors = HyperskillButtonDefaults.buttonColors(colorResource(id = R.color.layer_1)),
border = BorderStroke(1.dp, colorResource(id = R.color.button_tertiary)),
modifier = modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.paywall_mobile_only_continue_btn),
color = colorResource(id = R.color.button_tertiary)
)
}
}

@Composable
private fun TermsOfService(
modifier: Modifier = Modifier
Expand All @@ -153,11 +126,9 @@ fun PaywallContentPreview() {
HyperskillTheme {
PaywallContent(
buyButtonText = PaywallPreviewDefaults.BUY_BUTTON_TEXT,
isContinueWithLimitsButtonVisible = true,
priceText = PaywallPreviewDefaults.PRICE_TEXT,
onTermsOfServiceClick = {},
onBuySubscriptionClick = {},
onContinueWithLimitsClick = {}
onBuySubscriptionClick = {}
)
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
package org.hyperskill.app.android.paywall.ui

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.hyperskill.app.R
import org.hyperskill.app.android.core.extensions.findActivity
Expand Down Expand Up @@ -52,93 +63,142 @@ fun PaywallScreen(
viewModel.onBuySubscriptionClick(activity)
}
},
onContinueWithLimitsClick = viewModel::onContinueWithLimitsClick,
onCloseClick = viewModel::onCloseClick,
onRetryLoadingClick = viewModel::onRetryLoadingClicked,
onTermsOfServiceClick = viewModel::onTermsOfServiceClick
)
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun PaywallScreen(
viewState: ViewState,
onBackClick: () -> Unit,
onBuySubscriptionClick: () -> Unit,
onContinueWithLimitsClick: () -> Unit,
onCloseClick: () -> Unit,
onRetryLoadingClick: () -> Unit,
onTermsOfServiceClick: () -> Unit
) {
PaywallScaffold(
isToolbarVisible = viewState.isToolbarVisible,
onBackClick = onBackClick,
onCloseClick = onCloseClick
) { padding ->
val insets = WindowInsets.safeDrawing
when (val contentState = viewState.contentState) {
ViewStateContent.Idle -> {
// no op
}
ViewStateContent.Loading -> {
HyperskillProgressBar(
modifier = Modifier
.align(Alignment.Center)
)
}
ViewStateContent.Error ->
ScreenDataLoadingError(
errorMessage = stringResource(id = R.string.paywall_placeholder_error_description),
modifier = Modifier
.background(PaywallDefaults.BackgroundColor)
.windowInsetsPadding(insets)
) {
onRetryLoadingClick()
}
is ViewStateContent.Content ->
PaywallContent(
buyButtonText = contentState.buyButtonText,
priceText = contentState.priceText,
onBuySubscriptionClick = onBuySubscriptionClick,
onTermsOfServiceClick = onTermsOfServiceClick,
padding = padding
)
ViewStateContent.SubscriptionSyncLoading ->
SubscriptionSyncLoading(
modifier = Modifier.windowInsetsPadding(insets)
)
}
}
}

@Composable
private fun PaywallScaffold(
isToolbarVisible: Boolean,
onBackClick: () -> Unit,
onCloseClick: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable BoxScope.(PaddingValues) -> Unit
) {
Scaffold(
topBar = {
if (viewState.isToolbarVisible) {
if (isToolbarVisible) {
HyperskillTopAppBar(
title = stringResource(id = R.string.paywall_screen_title),
onNavigationIconClick = onBackClick,
backgroundColor = PaywallDefaults.BackgroundColor,
)
}
}
},
modifier = modifier
) { padding ->
Box(
Column(
modifier = Modifier
.fillMaxSize()
.background(PaywallDefaults.BackgroundColor)
.consumeStatusBarInsets(viewState.isToolbarVisible)
) {
val insets = WindowInsets.safeDrawing
when (val contentState = viewState.contentState) {
ViewStateContent.Idle -> {
// no op
}
ViewStateContent.Loading -> {
HyperskillProgressBar(
modifier = Modifier.align(Alignment.Center)
)
}
ViewStateContent.Error ->
ScreenDataLoadingError(
errorMessage = stringResource(id = R.string.paywall_placeholder_error_description),
modifier = Modifier
.background(PaywallDefaults.BackgroundColor)
.windowInsetsPadding(insets)
) {
onRetryLoadingClick()
}
is ViewStateContent.Content ->
PaywallContent(
buyButtonText = contentState.buyButtonText,
isContinueWithLimitsButtonVisible = contentState.isContinueWithLimitsButtonVisible,
priceText = contentState.priceText,
onBuySubscriptionClick = onBuySubscriptionClick,
onContinueWithLimitsClick = onContinueWithLimitsClick,
onTermsOfServiceClick = onTermsOfServiceClick,
padding = padding
)
ViewStateContent.SubscriptionSyncLoading ->
SubscriptionSyncLoading(
modifier = Modifier.windowInsetsPadding(insets)
)
if (!isToolbarVisible) {
CloseButton(
onClick = onCloseClick,
modifier = Modifier
.align(Alignment.End)
.padding(12.dp)
.windowInsetsPadding(WindowInsets.statusBars)
)
}
Box(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.consumeStatusBarInsets(isToolbarVisible),
content = {
content(padding)
}
)
}
}
}

@Composable
private fun CloseButton(
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
Box(
modifier = modifier
.requiredSize(32.dp)
.clip(CircleShape)
.clickable(onClick = onClick)
) {
Image(
painter = painterResource(id = org.hyperskill.app.android.R.drawable.ic_close_topic_completed),
contentDescription = null,
modifier = Modifier.align(Alignment.Center)
)
}
}

private class PaywallPreviewProvider : PreviewParameterProvider<ViewState> {
override val values: Sequence<ViewState>
get() = sequenceOf(
ViewState(
isToolbarVisible = true,
contentState = ViewStateContent.Content(
buyButtonText = PaywallPreviewDefaults.BUY_BUTTON_TEXT,
isContinueWithLimitsButtonVisible = false,
priceText = "$11.99 / month"
)
),
ViewState(
isToolbarVisible = false,
contentState = ViewStateContent.Content(
buyButtonText = PaywallPreviewDefaults.BUY_BUTTON_TEXT,
isContinueWithLimitsButtonVisible = true,
priceText = PaywallPreviewDefaults.PRICE_TEXT
)
),
Expand Down Expand Up @@ -176,7 +236,7 @@ fun PaywallScreenPreview(
viewState = viewState,
onBackClick = {},
onBuySubscriptionClick = {},
onContinueWithLimitsClick = {},
onCloseClick = {},
onRetryLoadingClick = {},
onTermsOfServiceClick = {}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ fun SubscriptionDetails(
SubscriptionOption(text = stringResource(id = SharedR.string.mobile_only_subscription_feature_1))
SubscriptionOption(text = stringResource(id = SharedR.string.mobile_only_subscription_feature_2))
SubscriptionOption(text = stringResource(id = SharedR.string.mobile_only_subscription_feature_3))
SubscriptionOption(text = stringResource(id = SharedR.string.mobile_only_subscription_feature_4))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.hyperskill.app.android.core.view.ui.fragment.setChildFragment
import org.hyperskill.app.android.core.view.ui.navigation.requireRouter
import org.hyperskill.app.android.databinding.FragmentStageStepWrapperBinding
import org.hyperskill.app.android.main.view.ui.navigation.MainScreenRouter
import org.hyperskill.app.android.paywall.navigation.PaywallScreen
import org.hyperskill.app.android.share_streak.fragment.ShareStreakDialogFragment
import org.hyperskill.app.android.stage_implementation.delegate.StageStepMenuDelegate
import org.hyperskill.app.android.step.view.delegate.StepDelegate
Expand All @@ -32,6 +33,7 @@ import org.hyperskill.app.step.domain.model.StepRoute
import org.hyperskill.app.step.presentation.StepFeature
import org.hyperskill.app.step.presentation.StepViewModel
import org.hyperskill.app.step_completion.presentation.StepCompletionFeature
import org.hyperskill.app.topic_completed_modal.presentation.TopicCompletedModalFeature
import ru.nobird.android.view.base.ui.delegate.ViewStateDelegate
import ru.nobird.android.view.base.ui.extension.argument
import ru.nobird.android.view.redux.ui.extension.reduxViewModel
Expand Down Expand Up @@ -207,12 +209,15 @@ class StageStepWrapperFragment :
stepViewModel.onRefuseStreakSharingClick(streak)
}

override fun navigateToStudyPlan() {
onNewMessage(StepCompletionFeature.Message.TopicCompletedModalGoToStudyPlanClicked)
}

override fun navigateToNextTopic() {
onNewMessage(StepCompletionFeature.Message.TopicCompletedModalContinueNextTopicClicked)
override fun navigateTo(destination: TopicCompletedModalFeature.Action.ViewAction.NavigateTo) {
when (destination) {
TopicCompletedModalFeature.Action.ViewAction.NavigateTo.NextTopic ->
onNewMessage(StepCompletionFeature.Message.TopicCompletedModalContinueNextTopicClicked)
TopicCompletedModalFeature.Action.ViewAction.NavigateTo.StudyPlan ->
onNewMessage(StepCompletionFeature.Message.TopicCompletedModalGoToStudyPlanClicked)
is TopicCompletedModalFeature.Action.ViewAction.NavigateTo.Paywall ->
requireRouter().navigateTo(PaywallScreen(destination.paywallTransitionSource))
}
}

override fun fullScrollDown() {
Expand Down
Loading
Loading