Skip to content

Commit 860f7be

Browse files
authored
Merge pull request #10 from RevenueCat/feature/entitlements
Implement checking the entitlement
2 parents 09cf823 + 187387d commit 860f7be

6 files changed

Lines changed: 44 additions & 9 deletions

File tree

core/data/src/main/kotlin/com/revenuecat/articles/paywall/coredata/repository/DetailsRepository.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
*/
1616
package com.revenuecat.articles.paywall.coredata.repository
1717

18+
import com.revenuecat.purchases.CustomerInfo
1819
import com.revenuecat.purchases.Offering
1920
import com.skydoves.sandwich.ApiResponse
2021
import kotlinx.coroutines.flow.Flow
2122

2223
interface DetailsRepository {
2324

2425
fun fetchOffering(): Flow<ApiResponse<Offering>>
26+
27+
fun fetchCustomerInfo(): Flow<CustomerInfo?>
2528
}

core/data/src/main/kotlin/com/revenuecat/articles/paywall/coredata/repository/DetailsRepositoryImpl.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ package com.revenuecat.articles.paywall.coredata.repository
1717

1818
import com.revenuecat.articles.paywall.core.network.CatArticlesDispatchers
1919
import com.revenuecat.articles.paywall.core.network.Dispatcher
20+
import com.revenuecat.purchases.CustomerInfo
2021
import com.revenuecat.purchases.Offering
2122
import com.revenuecat.purchases.Purchases
2223
import com.revenuecat.purchases.PurchasesException
24+
import com.revenuecat.purchases.awaitCustomerInfo
2325
import com.revenuecat.purchases.awaitOfferings
2426
import com.skydoves.sandwich.ApiResponse
2527
import kotlinx.coroutines.CoroutineDispatcher
@@ -43,4 +45,13 @@ internal class DetailsRepositoryImpl @Inject constructor(
4345
ApiResponse.exception(e)
4446
}
4547
}.flowOn(ioDispatcher)
48+
49+
override fun fetchCustomerInfo(): Flow<CustomerInfo?> = flow {
50+
try {
51+
val customerInfo = Purchases.sharedInstance.awaitCustomerInfo()
52+
emit(customerInfo)
53+
} catch (e: PurchasesException) {
54+
emit(null)
55+
}
56+
}
4657
}

core/designsystem/src/main/kotlin/com/revenuecat/articles/paywall/core/designsystem/component/FadeEdge.kt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,16 @@ import androidx.compose.ui.graphics.CompositingStrategy
2424
import androidx.compose.ui.graphics.graphicsLayer
2525

2626
fun Modifier.fadingEdge(
27+
isEnabled: Boolean = true,
2728
brush: Brush =
2829
Brush.verticalGradient(0.45f to Color.Red, 1f to Color.Transparent),
29-
) = this
30-
.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
31-
.drawWithContent {
32-
drawContent()
33-
drawRect(brush = brush, blendMode = BlendMode.DstIn)
34-
}
30+
) = if (isEnabled) {
31+
this
32+
.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
33+
.drawWithContent {
34+
drawContent()
35+
drawRect(brush = brush, blendMode = BlendMode.DstIn)
36+
}
37+
} else {
38+
this
39+
}

core/designsystem/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@
1919
<string name="paywall_title">Read best articles from industry leaders by subscribing Cat Articles 😻</string>
2020
<string name="paywall_description">This article is available to members only. \nUnlock it to access exclusive member benefits.</string>
2121
<string name="paywall_cta">Join Cat Articles</string>
22+
<string name="entitlement_premium">premium</string>
2223
</resources>

feature/article/src/main/kotlin/com/revenuecat/articles/paywal/feature/article/CatArticlesDetail.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ import com.revenuecat.articles.paywall.core.designsystem.theme.CatArticlesTheme
7070
import com.revenuecat.articles.paywall.core.model.Article
7171
import com.revenuecat.articles.paywall.core.model.MockUtils.mockArticle
7272
import com.revenuecat.articles.paywall.core.navigation.boundsTransform
73+
import com.revenuecat.purchases.CustomerInfo
7374
import com.revenuecat.purchases.InternalRevenueCatAPI
7475
import com.revenuecat.purchases.Offering
7576
import com.revenuecat.purchases.ui.revenuecatui.PaywallDialog
@@ -89,6 +90,7 @@ fun SharedTransitionScope.CatArticlesDetail(
8990
viewModel: CatArticlesDetailViewModel = hiltViewModel(),
9091
) {
9192
val article by viewModel.article.collectAsStateWithLifecycle()
93+
val customerInfo by viewModel.customerInfo.collectAsStateWithLifecycle()
9294
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
9395

9496
Column(
@@ -105,6 +107,7 @@ fun SharedTransitionScope.CatArticlesDetail(
105107
CatArticlesDetailContent(
106108
article = article!!,
107109
uiState = uiState,
110+
customerInfo = customerInfo,
108111
animatedVisibilityScope = animatedVisibilityScope,
109112
navigateUp = { viewModel.navigateUp() },
110113
)
@@ -116,14 +119,17 @@ fun SharedTransitionScope.CatArticlesDetail(
116119
private fun SharedTransitionScope.CatArticlesDetailContent(
117120
article: Article,
118121
uiState: DetailUiState,
122+
customerInfo: CustomerInfo?,
119123
animatedVisibilityScope: AnimatedVisibilityScope,
120124
navigateUp: () -> Unit,
121125
) {
122126
var palette by rememberPaletteState()
123127
val backgroundBrush by palette.paletteBackgroundBrush()
124128

125129
val context = LocalContext.current
126-
var isVisiblePaywallDialog by remember { mutableStateOf(false) }
130+
val entitlementIdentifier = stringResource(R.string.entitlement_premium)
131+
val isEntitled = customerInfo?.entitlements[entitlementIdentifier]?.isActive == true
132+
var isVisiblePaywallDialog by remember(customerInfo) { mutableStateOf(false) }
127133

128134
DetailsAppBar(
129135
article = article,
@@ -139,6 +145,7 @@ private fun SharedTransitionScope.CatArticlesDetailContent(
139145

140146
DetailsContent(
141147
article = article,
148+
isEntitled = isEntitled,
142149
onJoinClicked = {
143150
if (uiState is DetailUiState.Success) {
144151
isVisiblePaywallDialog = true
@@ -148,7 +155,7 @@ private fun SharedTransitionScope.CatArticlesDetailContent(
148155
},
149156
)
150157

151-
if (isVisiblePaywallDialog) {
158+
if (isVisiblePaywallDialog && !isEntitled) {
152159
val offering = (uiState as? DetailUiState.Success)?.offering ?: return
153160
PaywallDialog(
154161
PaywallDialogOptions.Builder()
@@ -236,13 +243,14 @@ private fun SharedTransitionScope.DetailsHeader(
236243
@Composable
237244
private fun DetailsContent(
238245
article: Article,
246+
isEntitled: Boolean,
239247
onJoinClicked: () -> Unit,
240248
) {
241249
Column(
242250
modifier = Modifier
243251
.fillMaxSize()
244252
.padding(12.dp)
245-
.fadingEdge(),
253+
.fadingEdge(isEnabled = !isEntitled),
246254
) {
247255
Text(
248256
text = article.title,
@@ -326,6 +334,7 @@ private fun CatArticlesDetailContentPreview() {
326334
availablePackages = listOf(),
327335
),
328336
),
337+
customerInfo = null,
329338
animatedVisibilityScope = this@AnimatedVisibility,
330339
navigateUp = {},
331340
)

feature/article/src/main/kotlin/com/revenuecat/articles/paywal/feature/article/CatArticlesDetailViewModel.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ class CatArticlesDetailViewModel @Inject constructor(
4141

4242
val article = savedStateHandle.getStateFlow<Article?>("article", null)
4343

44+
val customerInfo = repository.fetchCustomerInfo().stateIn(
45+
scope = viewModelScope,
46+
started = SharingStarted.WhileSubscribed(5000),
47+
initialValue = null,
48+
)
49+
4450
val uiState: StateFlow<DetailUiState> = repository.fetchOffering()
4551
.mapLatest { response ->
4652
response.fold(

0 commit comments

Comments
 (0)