From aa7d7fccc4a74f41cb078cff683d08e56fbf07a2 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Wed, 16 Oct 2024 19:47:24 +0100 Subject: [PATCH] Remove entitlements (#2078) --- core/entitlements/core/build.gradle.kts | 58 -------- .../tivi/entitlements/EntitlementManager.kt | 20 --- .../entitlements/EntitlementsComponent.kt | 8 -- .../EntitlementsPlatformComponent.kt | 11 -- .../EntitlementManagerInitializer.kt | 16 --- .../EntitlementsPlatformComponent.kt | 29 ---- .../RevenueCatEntitlementManager.kt | 64 --------- core/entitlements/ui/build.gradle.kts | 37 ----- core/entitlements/ui/lint-baseline.xml | 4 - .../app/tivi/entitlements/ui/Paywall.kt | 58 -------- .../app/tivi/entitlements/ui/Paywall.kt | 13 -- .../app/tivi/entitlements/ui/Paywall.kt | 46 ------ .../app/tivi/entitlements/ui/Paywall.jvm.kt | 15 -- domain/build.gradle.kts | 1 - .../ScheduleEpisodeNotifications.kt | 6 - gradle/libs.versions.toml | 6 - ios-app/Tivi/Podfile | 2 - ios-app/Tivi/Podfile.lock | 24 +--- ios-app/Tivi/Tivi StoreKit.storekit | 133 ------------------ ios-app/Tivi/Tivi.xcodeproj/project.pbxproj | 8 -- settings.gradle.kts | 2 - shared/common/build.gradle.kts | 1 - .../tivi/inject/SharedApplicationComponent.kt | 2 - tasks/build.gradle.kts | 1 - .../kotlin/app/tivi/tasks/TasksInitializer.kt | 6 +- ui/settings/build.gradle.kts | 1 - .../kotlin/app/tivi/settings/Settings.kt | 18 --- .../app/tivi/settings/SettingsPresenter.kt | 43 ++---- .../app/tivi/settings/SettingsUiState.kt | 3 - 29 files changed, 16 insertions(+), 620 deletions(-) delete mode 100644 core/entitlements/core/build.gradle.kts delete mode 100644 core/entitlements/core/src/commonMain/kotlin/app/tivi/entitlements/EntitlementManager.kt delete mode 100644 core/entitlements/core/src/commonMain/kotlin/app/tivi/entitlements/EntitlementsComponent.kt delete mode 100644 core/entitlements/core/src/jvmMain/kotlin/app/tivi/entitlements/EntitlementsPlatformComponent.kt delete mode 100644 core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/EntitlementManagerInitializer.kt delete mode 100644 core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/EntitlementsPlatformComponent.kt delete mode 100644 core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/RevenueCatEntitlementManager.kt delete mode 100644 core/entitlements/ui/build.gradle.kts delete mode 100644 core/entitlements/ui/lint-baseline.xml delete mode 100644 core/entitlements/ui/src/androidMain/kotlin/app/tivi/entitlements/ui/Paywall.kt delete mode 100644 core/entitlements/ui/src/commonMain/kotlin/app/tivi/entitlements/ui/Paywall.kt delete mode 100644 core/entitlements/ui/src/iosMain/kotlin/app/tivi/entitlements/ui/Paywall.kt delete mode 100644 core/entitlements/ui/src/jvmMain/kotlin/app/tivi/entitlements/ui/Paywall.jvm.kt delete mode 100644 ios-app/Tivi/Tivi StoreKit.storekit diff --git a/core/entitlements/core/build.gradle.kts b/core/entitlements/core/build.gradle.kts deleted file mode 100644 index 2cc5a57a9..000000000 --- a/core/entitlements/core/build.gradle.kts +++ /dev/null @@ -1,58 +0,0 @@ - -plugins { - id("app.tivi.android.library") - id("app.tivi.kotlin.multiplatform") - alias(libs.plugins.buildConfig) -} - -kotlin { - sourceSets { - commonMain { - dependencies { - api(projects.core.base) - } - } - - val mobileMain by creating { - dependsOn(commonMain.get()) - - dependencies { - api(libs.revenuecat.core) - implementation(libs.revenuecat.datetime) - implementation(libs.revenuecat.result) - } - } - - androidMain { - dependsOn(mobileMain) - } - - iosMain { - dependsOn(mobileMain) - } - } -} - -buildConfig { - packageName("app.tivi.entitlements") - - buildConfigField( - type = String::class.java, - name = "TIVI_REVENUECAT_ANDROID_API_KEY", - value = provider { properties["TIVI_REVENUECAT_ANDROID_API_KEY"]?.toString() ?: "" }, - ) - - buildConfigField( - type = String::class.java, - name = "TIVI_REVENUECAT_IOS_API_KEY", - value = provider { properties["TIVI_REVENUECAT_IOS_API_KEY"]?.toString() ?: "" }, - ) -} - -android { - namespace = "app.tivi.core.entitlements.core" -} - -configurations.configureEach { - exclude(group = "com.revenuecat.purchases", module = "purchases-store-amazon") -} diff --git a/core/entitlements/core/src/commonMain/kotlin/app/tivi/entitlements/EntitlementManager.kt b/core/entitlements/core/src/commonMain/kotlin/app/tivi/entitlements/EntitlementManager.kt deleted file mode 100644 index c2ae92784..000000000 --- a/core/entitlements/core/src/commonMain/kotlin/app/tivi/entitlements/EntitlementManager.kt +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf - -interface EntitlementManager { - fun setup() = Unit - suspend fun hasProEntitlement(): Boolean - fun observeProEntitlement(): Flow - - companion object { - val Always: EntitlementManager = object : EntitlementManager { - override suspend fun hasProEntitlement(): Boolean = true - override fun observeProEntitlement(): Flow = flowOf(true) - } - } -} diff --git a/core/entitlements/core/src/commonMain/kotlin/app/tivi/entitlements/EntitlementsComponent.kt b/core/entitlements/core/src/commonMain/kotlin/app/tivi/entitlements/EntitlementsComponent.kt deleted file mode 100644 index 3cb761d33..000000000 --- a/core/entitlements/core/src/commonMain/kotlin/app/tivi/entitlements/EntitlementsComponent.kt +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements - -expect interface EntitlementsPlatformComponent - -interface EntitlementsComponent : EntitlementsPlatformComponent diff --git a/core/entitlements/core/src/jvmMain/kotlin/app/tivi/entitlements/EntitlementsPlatformComponent.kt b/core/entitlements/core/src/jvmMain/kotlin/app/tivi/entitlements/EntitlementsPlatformComponent.kt deleted file mode 100644 index 5201e37c3..000000000 --- a/core/entitlements/core/src/jvmMain/kotlin/app/tivi/entitlements/EntitlementsPlatformComponent.kt +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements - -import me.tatarka.inject.annotations.Provides - -actual interface EntitlementsPlatformComponent { - @Provides - fun bindEntitlementManager(): EntitlementManager = EntitlementManager.Always -} diff --git a/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/EntitlementManagerInitializer.kt b/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/EntitlementManagerInitializer.kt deleted file mode 100644 index 9d055c849..000000000 --- a/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/EntitlementManagerInitializer.kt +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements - -import app.tivi.appinitializers.AppInitializer -import me.tatarka.inject.annotations.Inject - -@Inject -class EntitlementManagerInitializer( - private val entitlementManager: Lazy, -) : AppInitializer { - override fun initialize() { - entitlementManager.value.setup() - } -} diff --git a/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/EntitlementsPlatformComponent.kt b/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/EntitlementsPlatformComponent.kt deleted file mode 100644 index a9e030265..000000000 --- a/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/EntitlementsPlatformComponent.kt +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements - -import app.tivi.app.ApplicationInfo -import app.tivi.app.Flavor -import app.tivi.appinitializers.AppInitializer -import app.tivi.inject.ApplicationScope -import me.tatarka.inject.annotations.IntoSet -import me.tatarka.inject.annotations.Provides - -actual interface EntitlementsPlatformComponent { - @ApplicationScope - @Provides - fun provideEntitlementManager( - applicationInfo: ApplicationInfo, - revenueCatImpl: () -> RevenueCatEntitlementManager, - ): EntitlementManager = when (applicationInfo.flavor) { - // QA builds use different package/bundle ids so we can't use IAPs. Assume that QA == Pro - Flavor.Qa -> EntitlementManager.Always - // For standard build, we can use IAPs - Flavor.Standard -> revenueCatImpl() - } - - @Provides - @IntoSet - fun provideEntitlementManagerInitializer(impl: EntitlementManagerInitializer): AppInitializer = impl -} diff --git a/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/RevenueCatEntitlementManager.kt b/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/RevenueCatEntitlementManager.kt deleted file mode 100644 index d68cf49fd..000000000 --- a/core/entitlements/core/src/mobileMain/kotlin/app/tivi/entitlements/RevenueCatEntitlementManager.kt +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements - -import app.tivi.app.ApplicationInfo -import app.tivi.app.Platform -import com.revenuecat.purchases.kmp.EntitlementVerificationMode -import com.revenuecat.purchases.kmp.LogLevel -import com.revenuecat.purchases.kmp.Purchases -import com.revenuecat.purchases.kmp.PurchasesConfiguration -import com.revenuecat.purchases.kmp.ktx.awaitCustomerInfo -import kotlin.time.Duration.Companion.milliseconds -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flow -import me.tatarka.inject.annotations.Inject - -@Inject -class RevenueCatEntitlementManager( - private val applicationInfo: ApplicationInfo, -) : EntitlementManager { - - override fun setup() { - val apiKey = when (applicationInfo.platform) { - Platform.IOS -> BuildConfig.TIVI_REVENUECAT_IOS_API_KEY - Platform.ANDROID -> BuildConfig.TIVI_REVENUECAT_ANDROID_API_KEY - else -> null - } - - if (!apiKey.isNullOrEmpty()) { - if (applicationInfo.debugBuild) { - Purchases.logLevel = LogLevel.DEBUG - } - - Purchases.configure( - PurchasesConfiguration(apiKey = apiKey) { - verificationMode(EntitlementVerificationMode.INFORMATIONAL) - }, - ) - } - } - - override suspend fun hasProEntitlement(): Boolean { - return runCatching { - Purchases.sharedInstance.awaitCustomerInfo() - .entitlements[ENTITLEMENT_PRO_ID]?.isActive == true - }.getOrDefault(false) - } - - override fun observeProEntitlement(): Flow { - return flow { - while (true) { - emit(hasProEntitlement()) - delay(500.milliseconds) - } - }.distinctUntilChanged() - } - - private companion object { - const val ENTITLEMENT_PRO_ID = "pro" - } -} diff --git a/core/entitlements/ui/build.gradle.kts b/core/entitlements/ui/build.gradle.kts deleted file mode 100644 index 6da13e9d2..000000000 --- a/core/entitlements/ui/build.gradle.kts +++ /dev/null @@ -1,37 +0,0 @@ - -plugins { - id("app.tivi.android.library") - id("app.tivi.kotlin.multiplatform") - id("app.tivi.compose") -} - -kotlin { - sourceSets { - commonMain { - dependencies { - api(projects.core.entitlements.core) - api(projects.common.ui.compose) - } - } - - androidMain { - dependencies { - implementation(libs.revenuecat.ui) - } - } - - iosMain { - dependencies { - implementation(libs.revenuecat.ui) - } - } - } -} - -android { - namespace = "app.tivi.core.entitlements.ui" -} - -configurations.configureEach { - exclude(group = "com.revenuecat.purchases", module = "purchases-store-amazon") -} diff --git a/core/entitlements/ui/lint-baseline.xml b/core/entitlements/ui/lint-baseline.xml deleted file mode 100644 index c584e1295..000000000 --- a/core/entitlements/ui/lint-baseline.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/core/entitlements/ui/src/androidMain/kotlin/app/tivi/entitlements/ui/Paywall.kt b/core/entitlements/ui/src/androidMain/kotlin/app/tivi/entitlements/ui/Paywall.kt deleted file mode 100644 index 44da48c90..000000000 --- a/core/entitlements/ui/src/androidMain/kotlin/app/tivi/entitlements/ui/Paywall.kt +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements.ui - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.material3.BottomSheetDefaults -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.rememberModalBottomSheetState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.produceState -import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.ui.Modifier -import com.revenuecat.purchases.kmp.Purchases -import com.revenuecat.purchases.kmp.ktx.awaitOfferings -import com.revenuecat.purchases.kmp.ui.revenuecatui.Paywall as RevenueCatPaywall -import com.revenuecat.purchases.kmp.ui.revenuecatui.PaywallOptions - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -actual fun Paywall( - onDismissRequest: () -> Unit, - modifier: Modifier, -) { - val lastOnDismissRequest by rememberUpdatedState(onDismissRequest) - - val options by produceState(initialValue = null) { - val offerings = Purchases.sharedInstance.awaitOfferings() - - value = PaywallOptions(dismissRequest = lastOnDismissRequest) { - offering = offerings["pro"] - } - } - - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - - options?.let { - ModalBottomSheet( - sheetState = sheetState, - onDismissRequest = onDismissRequest, - dragHandle = null, - contentWindowInsets = { BottomSheetDefaults.windowInsets.only(WindowInsetsSides.Top) }, - modifier = modifier, - ) { - Box( - modifier = Modifier - .windowInsetsPadding(BottomSheetDefaults.windowInsets.only(WindowInsetsSides.Bottom)), - ) { - RevenueCatPaywall(it) - } - } - } -} diff --git a/core/entitlements/ui/src/commonMain/kotlin/app/tivi/entitlements/ui/Paywall.kt b/core/entitlements/ui/src/commonMain/kotlin/app/tivi/entitlements/ui/Paywall.kt deleted file mode 100644 index d7d130837..000000000 --- a/core/entitlements/ui/src/commonMain/kotlin/app/tivi/entitlements/ui/Paywall.kt +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements.ui - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier - -@Composable -expect fun Paywall( - onDismissRequest: () -> Unit, - modifier: Modifier = Modifier, -) diff --git a/core/entitlements/ui/src/iosMain/kotlin/app/tivi/entitlements/ui/Paywall.kt b/core/entitlements/ui/src/iosMain/kotlin/app/tivi/entitlements/ui/Paywall.kt deleted file mode 100644 index 005fd743c..000000000 --- a/core/entitlements/ui/src/iosMain/kotlin/app/tivi/entitlements/ui/Paywall.kt +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements.ui - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.produceState -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.ui.Modifier -import androidx.compose.ui.window.ComposeUIViewController -import app.tivi.common.compose.ui.PresentSheetViewController -import com.revenuecat.purchases.kmp.Purchases -import com.revenuecat.purchases.kmp.ktx.awaitOfferings -import com.revenuecat.purchases.kmp.ui.revenuecatui.Paywall as RevenueCatPaywall -import com.revenuecat.purchases.kmp.ui.revenuecatui.PaywallOptions -import platform.UIKit.UISheetPresentationControllerDetent - -@Composable -actual fun Paywall( - onDismissRequest: () -> Unit, - modifier: Modifier, -) { - val lastOnDismissRequest by rememberUpdatedState(onDismissRequest) - - val options by produceState(initialValue = null) { - val offerings = Purchases.sharedInstance.awaitOfferings() - - value = PaywallOptions(dismissRequest = lastOnDismissRequest) { - offering = offerings["pro"] - } - } - - val controller = remember { - ComposeUIViewController { - options?.let { RevenueCatPaywall(it) } - } - } - - PresentSheetViewController( - viewController = controller, - onDismissRequest = { onDismissRequest() }, - detents = listOf(UISheetPresentationControllerDetent.largeDetent()), - ) -} diff --git a/core/entitlements/ui/src/jvmMain/kotlin/app/tivi/entitlements/ui/Paywall.jvm.kt b/core/entitlements/ui/src/jvmMain/kotlin/app/tivi/entitlements/ui/Paywall.jvm.kt deleted file mode 100644 index 9bd546ac3..000000000 --- a/core/entitlements/ui/src/jvmMain/kotlin/app/tivi/entitlements/ui/Paywall.jvm.kt +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2024, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.entitlements.ui - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier - -@Composable -actual fun Paywall( - onDismissRequest: () -> Unit, - modifier: Modifier, -) { - // no-op -} diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index 6813a54d2..50c4b0c83 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -12,7 +12,6 @@ kotlin { dependencies { implementation(projects.core.base) implementation(projects.core.notifications.core) - api(projects.core.entitlements.core) api(projects.common.ui.resources) api(projects.data.models) diff --git a/domain/src/commonMain/kotlin/app/tivi/domain/interactors/ScheduleEpisodeNotifications.kt b/domain/src/commonMain/kotlin/app/tivi/domain/interactors/ScheduleEpisodeNotifications.kt index dbd359f22..46fe11b83 100644 --- a/domain/src/commonMain/kotlin/app/tivi/domain/interactors/ScheduleEpisodeNotifications.kt +++ b/domain/src/commonMain/kotlin/app/tivi/domain/interactors/ScheduleEpisodeNotifications.kt @@ -13,7 +13,6 @@ import app.tivi.data.episodes.SeasonsEpisodesRepository import app.tivi.data.models.Notification import app.tivi.data.models.NotificationChannel import app.tivi.domain.Interactor -import app.tivi.entitlements.EntitlementManager import app.tivi.util.AppCoroutineDispatchers import app.tivi.util.TiviDateFormatter import app.tivi.util.fmt @@ -33,19 +32,14 @@ class ScheduleEpisodeNotifications( seasonsEpisodesRepository: Lazy, notificationManager: Lazy, dateTimeFormatter: Lazy, - entitlementManager: Lazy, private val dispatchers: AppCoroutineDispatchers, private val applicationInfo: ApplicationInfo, ) : Interactor() { private val seasonsEpisodesRepository by seasonsEpisodesRepository private val notificationManager by notificationManager private val dateTimeFormatter by dateTimeFormatter - private val entitlementManager by entitlementManager override suspend fun doWork(params: Params) { - // TODO: we should do something better here - if (!entitlementManager.hasProEntitlement()) return - // We can do better here, but this is fine for now notificationManager.getPendingNotifications() .asSequence() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a661caa71..6ae8e4fd0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,6 @@ ktor = "2.3.12" paging = "3.3.2" spotless = "6.25.0" sqldelight = "2.0.2" -revenuecat = "1.1.2+13.5.0" licensee = "1.12.0" wire = "5.1.0" @@ -134,11 +133,6 @@ ktor-client-contentnegotiation = { module = "io.ktor:ktor-client-content-negotia playservices-blockstore = "com.google.android.gms:play-services-auth-blockstore:16.4.0" -revenuecat-core = { module = "com.revenuecat.purchases:purchases-kmp-core", version.ref = "revenuecat" } -revenuecat-datetime = { module = "com.revenuecat.purchases:purchases-kmp-datetime", version.ref = "revenuecat" } -revenuecat-result = { module = "com.revenuecat.purchases:purchases-kmp-result", version.ref = "revenuecat" } -revenuecat-ui = { module = "com.revenuecat.purchases:purchases-kmp-ui", version.ref = "revenuecat" } - screengrab = "tools.fastlane:screengrab:2.1.1" store = "org.mobilenativefoundation.store:store5:5.0.0" diff --git a/ios-app/Tivi/Podfile b/ios-app/Tivi/Podfile index 5eccc5eaa..01864d203 100644 --- a/ios-app/Tivi/Podfile +++ b/ios-app/Tivi/Podfile @@ -6,6 +6,4 @@ target 'Tivi' do pod 'AppAuth', '1.7.5' pod 'FirebaseAnalytics', '11.3.0' pod 'FirebaseCrashlytics', '11.3.0' - pod 'PurchasesHybridCommon', '13.2.0' - pod 'PurchasesHybridCommonUI', '13.2.0' end diff --git a/ios-app/Tivi/Podfile.lock b/ios-app/Tivi/Podfile.lock index c27dfdea1..11bda1fe1 100644 --- a/ios-app/Tivi/Podfile.lock +++ b/ios-app/Tivi/Podfile.lock @@ -23,7 +23,7 @@ PODS: - GoogleUtilities/Network (~> 8.0) - "GoogleUtilities/NSData+zlib (~> 8.0)" - nanopb (~> 3.30910.0) - - FirebaseCore (11.2.0): + - FirebaseCore (11.3.0): - FirebaseCoreInternal (~> 11.0) - GoogleUtilities/Environment (~> 8.0) - GoogleUtilities/Logger (~> 8.0) @@ -113,21 +113,11 @@ PODS: - PromisesObjC (2.4.0) - PromisesSwift (2.4.0): - PromisesObjC (= 2.4.0) - - PurchasesHybridCommon (13.2.0): - - RevenueCat (= 5.3.1) - - PurchasesHybridCommonUI (13.2.0): - - PurchasesHybridCommon (= 13.2.0) - - RevenueCatUI (= 5.3.1) - - RevenueCat (5.3.1) - - RevenueCatUI (5.3.1): - - RevenueCat (= 5.3.1) DEPENDENCIES: - AppAuth (= 1.7.5) - FirebaseAnalytics (= 11.3.0) - FirebaseCrashlytics (= 11.3.0) - - PurchasesHybridCommon (= 13.2.0) - - PurchasesHybridCommonUI (= 13.2.0) SPEC REPOS: trunk: @@ -146,15 +136,11 @@ SPEC REPOS: - nanopb - PromisesObjC - PromisesSwift - - PurchasesHybridCommon - - PurchasesHybridCommonUI - - RevenueCat - - RevenueCatUI SPEC CHECKSUMS: AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa FirebaseAnalytics: ce1593872635a5ebd715d0d3937fab195991ecc9 - FirebaseCore: a282032ae9295c795714ded2ec9c522fc237f8da + FirebaseCore: 8542de610f35f86196ba26cdb2544565a5157c8e FirebaseCoreExtension: 30bb063476ef66cd46925243d64ad8b2c8ac3264 FirebaseCoreInternal: ac26d09a70c730e497936430af4e60fb0c68ec4e FirebaseCrashlytics: ba7b6a55dc10393f6583d87d8600d0d3ab2671d8 @@ -167,11 +153,7 @@ SPEC CHECKSUMS: nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 - PurchasesHybridCommon: 20acf98303a9593f5d56b449459dcf16ea581a99 - PurchasesHybridCommonUI: fc8fa6ad78cfcdb6d82a8a865a8ae8b78724df53 - RevenueCat: b2d2555cbb1f4116d341af4c5f82269c8e4e499a - RevenueCatUI: 59b63f64505eac217af31f596e1ce3583734bba6 -PODFILE CHECKSUM: 6b3cb02b993171409783520d1f0bb403a22df800 +PODFILE CHECKSUM: fd1aec04db7cc41bfe52147d2cfd8608985cf8b3 COCOAPODS: 1.15.2 diff --git a/ios-app/Tivi/Tivi StoreKit.storekit b/ios-app/Tivi/Tivi StoreKit.storekit deleted file mode 100644 index d1d422026..000000000 --- a/ios-app/Tivi/Tivi StoreKit.storekit +++ /dev/null @@ -1,133 +0,0 @@ -{ - "identifier" : "70F9D390", - "nonRenewingSubscriptions" : [ - - ], - "products" : [ - - ], - "settings" : { - "_applicationInternalID" : "6450872484", - "_developerTeamID" : "GLF74Y6P9T", - "_failTransactionsEnabled" : false, - "_lastSynchronizedDate" : 743672780.358706, - "_locale" : "en_US", - "_storefront" : "USA", - "_storeKitErrors" : [ - { - "current" : null, - "enabled" : false, - "name" : "Load Products" - }, - { - "current" : null, - "enabled" : false, - "name" : "Purchase" - }, - { - "current" : null, - "enabled" : false, - "name" : "Verification" - }, - { - "current" : null, - "enabled" : false, - "name" : "App Store Sync" - }, - { - "current" : null, - "enabled" : false, - "name" : "Subscription Status" - }, - { - "current" : null, - "enabled" : false, - "name" : "App Transaction" - }, - { - "current" : null, - "enabled" : false, - "name" : "Manage Subscriptions Sheet" - }, - { - "current" : null, - "enabled" : false, - "name" : "Refund Request Sheet" - }, - { - "current" : null, - "enabled" : false, - "name" : "Offer Code Redeem Sheet" - } - ] - }, - "subscriptionGroups" : [ - { - "id" : "21513339", - "localizations" : [ - - ], - "name" : "Tivi Pro", - "subscriptions" : [ - { - "adHocOffers" : [ - - ], - "codeOffers" : [ - - ], - "displayPrice" : "9.99", - "familyShareable" : false, - "groupNumber" : 2, - "internalID" : "6557075690", - "introductoryOffer" : null, - "localizations" : [ - { - "description" : "Pro Access", - "displayName" : "Pro Access", - "locale" : "en_GB" - } - ], - "productID" : "tivi_9.99_1year", - "recurringSubscriptionPeriod" : "P1Y", - "referenceName" : "Annual $9.99", - "subscriptionGroupID" : "21513339", - "type" : "RecurringSubscription" - }, - { - "adHocOffers" : [ - - ], - "codeOffers" : [ - - ], - "displayPrice" : "0.99", - "familyShareable" : false, - "groupNumber" : 1, - "internalID" : "6557075846", - "introductoryOffer" : null, - "localizations" : [ - { - "description" : "Pro Access", - "displayName" : "Pro Access", - "locale" : "en_GB" - } - ], - "productID" : "tivi_0.99_1month", - "recurringSubscriptionPeriod" : "P1M", - "referenceName" : "Monthly $0.99", - "subscriptionGroupID" : "21513339", - "type" : "RecurringSubscription" - } - ] - } - ], - "subscriptionOffersKeyPair" : { - "id" : "2EA2B889", - "privateKey" : "MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgXLWHaLKlyzebG8yvslxLunqxxAO/KqHjZwJrbot3psWgCgYIKoZIzj0DAQehRANCAAQXiplnw2/KD9Xs56acHCObwKMtvvrzIt1YsompLiEIAxE6J8+MHDKhmO7+rLVV/xtqdtSyGa27WMxayRh9+W4G" - }, - "version" : { - "major" : 3, - "minor" : 0 - } -} diff --git a/ios-app/Tivi/Tivi.xcodeproj/project.pbxproj b/ios-app/Tivi/Tivi.xcodeproj/project.pbxproj index 6cb5e72a6..27987ec42 100644 --- a/ios-app/Tivi/Tivi.xcodeproj/project.pbxproj +++ b/ios-app/Tivi/Tivi.xcodeproj/project.pbxproj @@ -11,8 +11,6 @@ 38137D722A55D6E200A687CC /* Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38137D712A55D6E200A687CC /* Auth.swift */; }; 38137D772A584D1900A687CC /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 38137D762A584D1900A687CC /* Settings.bundle */; }; 385297C12C2974F3004BD20A /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385297C02C2974F3004BD20A /* Extensions.swift */; }; - 388B425E2C538BC9006ADC84 /* Tivi StoreKit.storekit in Resources */ = {isa = PBXBuildFile; fileRef = 388B425D2C538BC9006ADC84 /* Tivi StoreKit.storekit */; }; - 388B42632C53ADC9006ADC84 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 388B42622C53ADC9006ADC84 /* StoreKit.framework */; }; 833349382A4CCCEE00F464FE /* TiviApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 833349372A4CCCEE00F464FE /* TiviApp.swift */; }; 8333493A2A4CCCEE00F464FE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 833349392A4CCCEE00F464FE /* ContentView.swift */; }; 8333493C2A4CCCEF00F464FE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8333493B2A4CCCEF00F464FE /* Assets.xcassets */; }; @@ -38,8 +36,6 @@ 38137D762A584D1900A687CC /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; 38282FFD2A4F318E00E7929E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 385297C02C2974F3004BD20A /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; - 388B425D2C538BC9006ADC84 /* Tivi StoreKit.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Tivi StoreKit.storekit"; sourceTree = ""; }; - 388B42622C53ADC9006ADC84 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; 5D263D863B021AC431BCD3BC /* Pods-Tivi.prod release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tivi.prod release.xcconfig"; path = "Target Support Files/Pods-Tivi/Pods-Tivi.prod release.xcconfig"; sourceTree = ""; }; 7D46A0EC97E7FFD72A98929D /* Pods_Tivi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tivi.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 833349342A4CCCEE00F464FE /* Tivi QA Dev.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Tivi QA Dev.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -71,7 +67,6 @@ buildActionMask = 2147483647; files = ( 042DF22224841D8E4354F8A2 /* Pods_Tivi.framework in Frameworks */, - 388B42632C53ADC9006ADC84 /* StoreKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -88,7 +83,6 @@ 8333492B2A4CCCEE00F464FE = { isa = PBXGroup; children = ( - 388B425D2C538BC9006ADC84 /* Tivi StoreKit.storekit */, 838A694C2C4B977C00D10870 /* xcconfig */, 833349362A4CCCEE00F464FE /* Tivi */, 38137D762A584D1900A687CC /* Settings.bundle */, @@ -168,7 +162,6 @@ 83AB5FFF2A51F3FD007FC216 /* Frameworks */ = { isa = PBXGroup; children = ( - 388B42622C53ADC9006ADC84 /* StoreKit.framework */, 7D46A0EC97E7FFD72A98929D /* Pods_Tivi.framework */, ); name = Frameworks; @@ -271,7 +264,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 388B425E2C538BC9006ADC84 /* Tivi StoreKit.storekit in Resources */, 38137D772A584D1900A687CC /* Settings.bundle in Resources */, 8333493F2A4CCCEF00F464FE /* Preview Assets.xcassets in Resources */, 8333493C2A4CCCEF00F464FE /* Assets.xcassets in Resources */, diff --git a/settings.gradle.kts b/settings.gradle.kts index 22070bee8..397c94282 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -79,8 +79,6 @@ rootProject.name = "tivi" include( ":core:analytics", ":core:base", - ":core:entitlements:core", - ":core:entitlements:ui", ":core:logging", ":core:performance", ":core:permissions", diff --git a/shared/common/build.gradle.kts b/shared/common/build.gradle.kts index 14b87a23f..a4cd661ea 100644 --- a/shared/common/build.gradle.kts +++ b/shared/common/build.gradle.kts @@ -17,7 +17,6 @@ kotlin { dependencies { api(projects.core.base) api(projects.core.analytics) - api(projects.core.entitlements.core) api(projects.core.notifications.core) api(projects.core.logging) api(projects.core.performance) diff --git a/shared/common/src/commonMain/kotlin/app/tivi/inject/SharedApplicationComponent.kt b/shared/common/src/commonMain/kotlin/app/tivi/inject/SharedApplicationComponent.kt index 8ebff9a60..a5fce6cbd 100644 --- a/shared/common/src/commonMain/kotlin/app/tivi/inject/SharedApplicationComponent.kt +++ b/shared/common/src/commonMain/kotlin/app/tivi/inject/SharedApplicationComponent.kt @@ -24,7 +24,6 @@ import app.tivi.data.traktauth.TraktAuthComponent import app.tivi.data.traktusers.TraktUsersBinds import app.tivi.data.trendingshows.TrendingShowsBinds import app.tivi.data.watchedshows.WatchedShowsBinds -import app.tivi.entitlements.EntitlementsComponent import app.tivi.navigation.DeepLinker import app.tivi.settings.PreferencesComponent import app.tivi.tasks.TasksComponent @@ -50,7 +49,6 @@ interface SharedApplicationComponent : TmdbComponent, TraktComponent, AnalyticsComponent, - EntitlementsComponent, LoggerComponent, NotificationsComponent, PerformanceComponent, diff --git a/tasks/build.gradle.kts b/tasks/build.gradle.kts index af07dd37d..5ccc9e00f 100644 --- a/tasks/build.gradle.kts +++ b/tasks/build.gradle.kts @@ -13,7 +13,6 @@ kotlin { dependencies { implementation(projects.core.base) implementation(projects.core.notifications.core) - implementation(projects.core.entitlements.core) implementation(projects.domain) implementation(libs.kotlininject.runtime) } diff --git a/tasks/src/commonMain/kotlin/app/tivi/tasks/TasksInitializer.kt b/tasks/src/commonMain/kotlin/app/tivi/tasks/TasksInitializer.kt index e5ef717ad..1a9fbd843 100644 --- a/tasks/src/commonMain/kotlin/app/tivi/tasks/TasksInitializer.kt +++ b/tasks/src/commonMain/kotlin/app/tivi/tasks/TasksInitializer.kt @@ -4,7 +4,6 @@ package app.tivi.tasks import app.tivi.appinitializers.AppInitializer -import app.tivi.entitlements.EntitlementManager import app.tivi.inject.ApplicationCoroutineScope import app.tivi.settings.TiviPreferences import app.tivi.util.launchOrThrow @@ -14,12 +13,10 @@ import me.tatarka.inject.annotations.Inject class TasksInitializer( tasks: Lazy, preferences: Lazy, - entitlementManager: Lazy, private val coroutineScope: ApplicationCoroutineScope, ) : AppInitializer { private val tasks by tasks private val preferences by preferences - private val entitlementManager by entitlementManager override fun initialize() { tasks.setup() @@ -29,9 +26,8 @@ class TasksInitializer( coroutineScope.launchOrThrow { preferences.episodeAiringNotificationsEnabled.flow .collect { enabled -> - val isPro = entitlementManager.hasProEntitlement() when { - enabled && isPro -> tasks.scheduleEpisodeNotifications() + enabled -> tasks.scheduleEpisodeNotifications() else -> tasks.cancelEpisodeNotifications() } } diff --git a/ui/settings/build.gradle.kts b/ui/settings/build.gradle.kts index 1a5422bb3..538f5d2e3 100644 --- a/ui/settings/build.gradle.kts +++ b/ui/settings/build.gradle.kts @@ -17,7 +17,6 @@ kotlin { commonMain { dependencies { implementation(projects.core.base) - implementation(projects.core.entitlements.ui) implementation(projects.core.permissions) implementation(projects.core.preferences) implementation(projects.domain) diff --git a/ui/settings/src/commonMain/kotlin/app/tivi/settings/Settings.kt b/ui/settings/src/commonMain/kotlin/app/tivi/settings/Settings.kt index 18a9d8b0b..3df92d25a 100644 --- a/ui/settings/src/commonMain/kotlin/app/tivi/settings/Settings.kt +++ b/ui/settings/src/commonMain/kotlin/app/tivi/settings/Settings.kt @@ -12,13 +12,11 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AutoMode import androidx.compose.material.icons.filled.DarkMode import androidx.compose.material.icons.filled.LightMode -import androidx.compose.material.icons.filled.Loyalty import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilledIconToggleButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable @@ -66,7 +64,6 @@ import app.tivi.common.ui.resources.settings_theme_title import app.tivi.common.ui.resources.settings_title import app.tivi.common.ui.resources.settings_ui_category_title import app.tivi.common.ui.resources.view_privacy_policy -import app.tivi.entitlements.ui.Paywall import app.tivi.screens.SettingsScreen import app.tivi.util.launchOrThrow import com.slack.circuit.overlay.ContentWithOverlays @@ -104,12 +101,6 @@ internal fun Settings( // treats it as stable. See: https://issuetracker.google.com/issues/256100927 val eventSink = state.eventSink - if (state.proUpsellVisible) { - Paywall( - onDismissRequest = { eventSink(SettingsUiEvent.DismissProUpsell) }, - ) - } - ContentWithOverlays { HazeScaffold( topBar = { @@ -194,15 +185,6 @@ internal fun Settings( summaryOff = stringResource(Res.string.settings_notifications_airing_episodes_summary), onCheckClicked = { eventSink(SettingsUiEvent.ToggleAiringEpisodeNotificationsEnabled) }, checked = state.airingEpisodeNotificationsEnabled, - beforeControl = { - if (!state.isPro) { - Icon( - imageVector = Icons.Default.Loyalty, - tint = MaterialTheme.colorScheme.primary, - contentDescription = null, - ) - } - }, ) } diff --git a/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsPresenter.kt b/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsPresenter.kt index 17dfaa142..2a1e9c12a 100644 --- a/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsPresenter.kt +++ b/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsPresenter.kt @@ -7,10 +7,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import app.tivi.app.ApplicationInfo import app.tivi.app.Flavor import app.tivi.common.compose.collectAsState @@ -20,7 +16,6 @@ import app.tivi.core.permissions.PermissionsController import app.tivi.core.permissions.performPermissionedAction import app.tivi.data.traktauth.TraktAuthState import app.tivi.domain.observers.ObserveTraktAuthState -import app.tivi.entitlements.EntitlementManager import app.tivi.screens.DevSettingsScreen import app.tivi.screens.LicensesScreen import app.tivi.screens.SettingsScreen @@ -54,13 +49,11 @@ class SettingsPresenter( @Assisted private val navigator: Navigator, preferences: Lazy, permissionsController: Lazy, - entitlements: Lazy, observeTraktAuthState: Lazy, private val applicationInfo: ApplicationInfo, ) : Presenter { private val preferences by preferences private val permissionsController by permissionsController - private val entitlements by entitlements private val observeTraktAuthState by observeTraktAuthState @Composable @@ -74,11 +67,7 @@ class SettingsPresenter( val authState by observeTraktAuthState.flow.collectAsState(TraktAuthState.LOGGED_OUT) - val isPro by produceState(initialValue = false, entitlements) { - entitlements.observeProEntitlement().collect { value = it } - } val notificationsEnabled by preferences.episodeAiringNotificationsEnabled.collectAsState() - var proUpsellVisible by remember { mutableStateOf(false) } LaunchedEffect(observeTraktAuthState) { observeTraktAuthState(Unit) @@ -115,24 +104,20 @@ class SettingsPresenter( } SettingsUiEvent.ToggleAiringEpisodeNotificationsEnabled -> { - if (isPro) { - launchOrThrow { - if (preferences.episodeAiringNotificationsEnabled.get()) { - // If we're enabled, and being turned off, we don't need to mess with permissions - preferences.episodeAiringNotificationsEnabled.set(false) - } else { - // If we're disabled, and being turned on, we need to check our permissions - permissionsController.performPermissionedAction(REMOTE_NOTIFICATION) { state -> - if (state == PermissionState.Granted) { - preferences.episodeAiringNotificationsEnabled.set(true) - } else { - permissionsController.openAppSettings() - } + launchOrThrow { + if (preferences.episodeAiringNotificationsEnabled.get()) { + // If we're enabled, and being turned off, we don't need to mess with permissions + preferences.episodeAiringNotificationsEnabled.set(false) + } else { + // If we're disabled, and being turned on, we need to check our permissions + permissionsController.performPermissionedAction(REMOTE_NOTIFICATION) { state -> + if (state == PermissionState.Granted) { + preferences.episodeAiringNotificationsEnabled.set(true) + } else { + permissionsController.openAppSettings() } } } - } else { - proUpsellVisible = true } } @@ -143,8 +128,6 @@ class SettingsPresenter( SettingsUiEvent.NavigateOpenSource -> navigator.goTo(LicensesScreen) SettingsUiEvent.NavigateDeveloperSettings -> navigator.goTo(DevSettingsScreen) - SettingsUiEvent.DismissProUpsell -> proUpsellVisible = false - SettingsUiEvent.DeleteAccount -> { navigator.goTo(UrlScreen("https://trakt.tv/settings")) } @@ -160,11 +143,9 @@ class SettingsPresenter( ignoreSpecials = ignoreSpecials, crashDataReportingEnabled = crashDataReportingEnabled, analyticsDataReportingEnabled = analyticsDataReportingEnabled, - airingEpisodeNotificationsEnabled = notificationsEnabled && isPro, + airingEpisodeNotificationsEnabled = notificationsEnabled, applicationInfo = applicationInfo, showDeveloperSettings = applicationInfo.flavor == Flavor.Qa, - proUpsellVisible = proUpsellVisible, - isPro = isPro, isLoggedIn = authState == TraktAuthState.LOGGED_IN, showDeleteAccount = authState == TraktAuthState.LOGGED_IN, eventSink = wrapEventSink(eventSink), diff --git a/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsUiState.kt b/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsUiState.kt index b1b1be864..1596ffed2 100644 --- a/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsUiState.kt +++ b/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsUiState.kt @@ -21,8 +21,6 @@ data class SettingsUiState( val airingEpisodeNotificationsEnabled: Boolean, val applicationInfo: ApplicationInfo, val showDeveloperSettings: Boolean, - val proUpsellVisible: Boolean, - val isPro: Boolean, val isLoggedIn: Boolean, val showDeleteAccount: Boolean, val eventSink: (SettingsUiEvent) -> Unit, @@ -39,7 +37,6 @@ sealed interface SettingsUiEvent : CircuitUiEvent { data object ToggleCrashDataReporting : SettingsUiEvent data object ToggleAnalyticsDataReporting : SettingsUiEvent data object ToggleAiringEpisodeNotificationsEnabled : SettingsUiEvent - data object DismissProUpsell : SettingsUiEvent data object DeleteAccount : SettingsUiEvent data class SetTheme(val theme: TiviPreferences.Theme) : SettingsUiEvent }