diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/home/view/ui/fragment/HomeFragment.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/home/view/ui/fragment/HomeFragment.kt
index b8f216b70b..b39afcfc1d 100644
--- a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/home/view/ui/fragment/HomeFragment.kt
+++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/home/view/ui/fragment/HomeFragment.kt
@@ -207,8 +207,8 @@ class HomeFragment :
val homeState = state.homeState
if (homeState is HomeFeature.HomeState.Content) {
- renderProblemOfDay(viewBinding, homeState.problemOfDayState, homeState.areProblemsLimited)
- renderTopicsRepetition(homeState.repetitionsState, homeState.areProblemsLimited)
+ renderProblemOfDay(viewBinding, homeState.problemOfDayState, homeState.isProblemsLimitEnabled)
+ renderTopicsRepetition(homeState.repetitionsState, homeState.isProblemsLimitEnabled)
}
renderChallengeCard(state.challengeWidgetViewState)
@@ -242,19 +242,19 @@ class HomeFragment :
private fun renderProblemOfDay(
viewBinding: FragmentHomeBinding,
state: HomeFeature.ProblemOfDayState,
- areProblemsLimited: Boolean
+ isProblemsLimitEnabled: Boolean
) {
problemOfDayCardFormDelegate.render(
dateFormatter = dateFormatter,
binding = viewBinding.homeScreenProblemOfDayCard,
state = state,
- areProblemsLimited = areProblemsLimited
+ areProblemsLimited = isProblemsLimitEnabled
)
}
private fun renderTopicsRepetition(
repetitionsState: HomeFeature.RepetitionsState,
- areProblemsLimited: Boolean
+ isProblemsLimitEnabled: Boolean
) {
viewBinding.homeScreenTopicsRepetitionCard.root.isVisible =
repetitionsState is HomeFeature.RepetitionsState.Available
@@ -263,7 +263,7 @@ class HomeFragment :
context = requireContext(),
binding = viewBinding.homeScreenTopicsRepetitionCard,
recommendedRepetitionsCount = repetitionsState.recommendedRepetitionsCount,
- areProblemsLimited = areProblemsLimited
+ isProblemsLimitEnabled = isProblemsLimitEnabled
)
}
}
diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/topics_repetitions/view/delegate/TopicsRepetitionCardFormDelegate.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/topics_repetitions/view/delegate/TopicsRepetitionCardFormDelegate.kt
index 267c2eb413..09a5a82485 100644
--- a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/topics_repetitions/view/delegate/TopicsRepetitionCardFormDelegate.kt
+++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/topics_repetitions/view/delegate/TopicsRepetitionCardFormDelegate.kt
@@ -10,7 +10,7 @@ class TopicsRepetitionCardFormDelegate {
context: Context,
binding: LayoutTopicsRepetitionCardBinding,
recommendedRepetitionsCount: Int,
- areProblemsLimited: Boolean
+ isProblemsLimitEnabled: Boolean
) {
with(binding) {
topicsRepetitionBackgroundImageView.setImageResource(
@@ -49,7 +49,7 @@ class TopicsRepetitionCardFormDelegate {
}
)
topicsRepetitionUnlimitedBadge.isVisible =
- areProblemsLimited && recommendedRepetitionsCount > 0
+ isProblemsLimitEnabled && recommendedRepetitionsCount > 0
}
}
}
\ No newline at end of file
diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml
index b22a201a28..e6d290dfee 100644
--- a/config/detekt/baseline.xml
+++ b/config/detekt/baseline.xml
@@ -242,7 +242,6 @@
ReturnCount:SearchReducer.kt$SearchReducer$private fun handleSearchResultsItemClickedMessage( state: State, message: Message.SearchResultsItemClicked ): SearchReducerResult?
ReturnCount:SharedDateFormatter.kt$SharedDateFormatter$fun formatTimeDistance(millis: Long): String
ReturnCount:StateExtentions.kt$internal fun ChallengeWidgetFeature.State.Content.setCurrentChallengeIntervalProgressAsCompleted(): Challenge?
- ReturnCount:StepQuizActionDispatcher.kt$StepQuizActionDispatcher$private suspend fun handleUpdateProblemsLimitAction( action: InternalAction.UpdateProblemsLimit, onNewMessage: (Message) -> Unit )
ReturnCount:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleDeleteButtonClicked( state: State ): StepQuizCodeBlanksReducerResult?
ReturnCount:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleSuggestionClicked( state: State, message: Message.SuggestionClicked ): StepQuizCodeBlanksReducerResult?
ReturnCount:StepQuizHintsInteractor.kt$StepQuizHintsInteractor$suspend fun getLastSeenHint(stepId: Long): Comment?
@@ -282,6 +281,7 @@
TooManyFunctions:SharedDateFormatter.kt$SharedDateFormatter
TooManyFunctions:StepActionDispatcher.kt$StepActionDispatcher : CoroutineActionDispatcher
TooManyFunctions:StudyPlanWidgetDelegate.kt$StudyPlanWidgetDelegate
+ TooManyFunctions:SubscriptionsInteractor.kt$SubscriptionsInteractor
TopLevelPropertyNaming:HyperskillNotificationChannel.kt$private const val dailyReminderId = "dailyReminderChannel"
TopLevelPropertyNaming:HyperskillNotificationChannel.kt$private const val otherId = "otherChannel"
TopLevelPropertyNaming:HyperskillNotificationChannel.kt$private const val regularLearningRemindersId = "regularLearningRemindersChannel"
diff --git a/iosHyperskillApp/iosHyperskillApp/Sources/Modules/Home/Views/HomeView.swift b/iosHyperskillApp/iosHyperskillApp/Sources/Modules/Home/Views/HomeView.swift
index a628d46288..99edbd1d75 100644
--- a/iosHyperskillApp/iosHyperskillApp/Sources/Modules/Home/Views/HomeView.swift
+++ b/iosHyperskillApp/iosHyperskillApp/Sources/Modules/Home/Views/HomeView.swift
@@ -87,7 +87,7 @@ struct HomeView: View {
ProblemOfDayAssembly(
problemOfDayState: data.problemOfDayState,
- isFreemiumEnabled: data.areProblemsLimited,
+ isFreemiumEnabled: data.isProblemsLimitEnabled,
output: viewModel
)
.makeModule()
@@ -96,7 +96,7 @@ struct HomeView: View {
TopicsRepetitionsCardView(
topicsToRepeatCount: Int(availableRepetitionsState.recommendedRepetitionsCount),
onTap: viewModel.doTopicsRepetitionsPresentation,
- isFreemiumEnabled: data.areProblemsLimited
+ isFreemiumEnabled: data.isProblemsLimitEnabled
)
}
}
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/analytic/domain/interactor/AnalyticInteractor.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/analytic/domain/interactor/AnalyticInteractor.kt
index a5e03338db..89c276a15b 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/analytic/domain/interactor/AnalyticInteractor.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/analytic/domain/interactor/AnalyticInteractor.kt
@@ -19,14 +19,20 @@ import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionSta
import ru.nobird.app.core.model.mapOfNotNull
class AnalyticInteractor(
+ // Provide CurrentSubscriptionStateRepository lazily
+ // because it depends on AnalyticInteractor
+ currentSubscriptionStateRepositoryProvider: () -> CurrentSubscriptionStateRepository,
private val currentProfileStateRepository: CurrentProfileStateRepository,
- private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
private val notificationInteractor: NotificationInteractor,
private val platform: Platform,
private val analyticEngines: List,
override val eventMonitor: AnalyticEventMonitor?
) : Analytic {
+ private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository by lazy {
+ currentSubscriptionStateRepositoryProvider.invoke()
+ }
+
private var userProperties: MutableMap = mutableMapOf()
override fun reportEvent(event: AnalyticEvent, forceReportEvent: Boolean) {
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/analytic/injection/AnalyticComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/analytic/injection/AnalyticComponentImpl.kt
index ba12b70a8c..e34aec5902 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/analytic/injection/AnalyticComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/analytic/injection/AnalyticComponentImpl.kt
@@ -37,7 +37,9 @@ class AnalyticComponentImpl(
AnalyticInteractor(
analyticEngines = analyticEngines,
currentProfileStateRepository = appGraph.profileDataComponent.currentProfileStateRepository,
- currentSubscriptionStateRepository = appGraph.stateRepositoriesComponent.currentSubscriptionStateRepository,
+ currentSubscriptionStateRepositoryProvider = {
+ appGraph.stateRepositoriesComponent.currentSubscriptionStateRepository
+ },
notificationInteractor = appGraph.buildNotificationComponent().notificationInteractor,
eventMonitor = BatchAnalyticEventMonitor(listOfNotNull(sentryInteractor, loggableAnalyticEventMonitor)),
platform = appGraph.commonComponent.platform
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/core/data/repository/BaseStateRepository.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/core/data/repository/BaseStateRepository.kt
index e19db08830..12c29e8cfc 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/core/data/repository/BaseStateRepository.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/core/data/repository/BaseStateRepository.kt
@@ -4,8 +4,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.hyperskill.app.core.domain.DataSourceType
@@ -43,7 +43,7 @@ abstract class BaseStateRepository : StateRepository {
*
* @return shared flow
*/
- override val changes: SharedFlow
+ override val changes: Flow
get() = mutableSharedFlow
/**
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/core/domain/repository/StateRepository.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/core/domain/repository/StateRepository.kt
index 50c4e1ee4f..b91564b2f5 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/core/domain/repository/StateRepository.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/core/domain/repository/StateRepository.kt
@@ -1,6 +1,6 @@
package org.hyperskill.app.core.domain.repository
-import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
interface StateRepository {
@@ -26,7 +26,7 @@ interface StateRepository {
*
* @return shared flow
*/
- val changes: SharedFlow
+ val changes: Flow
/**
* Update state locally in app.
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/core/injection/StateRepositoriesComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/core/injection/StateRepositoriesComponentImpl.kt
index f5293cc2c1..69f0ee84cb 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/core/injection/StateRepositoriesComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/core/injection/StateRepositoriesComponentImpl.kt
@@ -6,6 +6,7 @@ import org.hyperskill.app.gamification_toolbar.remote.GamificationToolbarRemoteD
import org.hyperskill.app.learning_activities.data.repository.NextLearningActivityStateRepositoryImpl
import org.hyperskill.app.learning_activities.domain.repository.NextLearningActivityStateRepository
import org.hyperskill.app.learning_activities.remote.LearningActivitiesRemoteDataSourceImpl
+import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.study_plan.data.repository.CurrentStudyPlanStateRepositoryImpl
import org.hyperskill.app.study_plan.domain.repository.CurrentStudyPlanStateRepository
import org.hyperskill.app.study_plan.remote.StudyPlanRemoteDataSourceImpl
@@ -20,6 +21,10 @@ class StateRepositoriesComponentImpl(appGraph: AppGraph) : StateRepositoriesComp
private val authorizedHttpClient = appGraph.networkComponent.authorizedHttpClient
+ private val featuresDataSource = appGraph.profileDataComponent.featuresDataSource
+
+ private val purchaseInteractor: PurchaseInteractor = appGraph.buildPurchaseComponent().purchaseInteractor
+
/**
* Current subscription
*/
@@ -34,7 +39,12 @@ class StateRepositoriesComponentImpl(appGraph: AppGraph) : StateRepositoriesComp
}
override val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository =
- CurrentSubscriptionStateRepositoryImpl(subscriptionsRemoteDataSource, currentSubscriptionStateHolder)
+ CurrentSubscriptionStateRepositoryImpl(
+ subscriptionsRemoteDataSource = subscriptionsRemoteDataSource,
+ stateHolder = currentSubscriptionStateHolder,
+ featuresDataSource = featuresDataSource,
+ purchaseInteractor = purchaseInteractor
+ )
/**
* Study plan
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/features/data/source/FeaturesDataSource.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/features/data/source/FeaturesDataSource.kt
new file mode 100644
index 0000000000..b0317c7436
--- /dev/null
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/features/data/source/FeaturesDataSource.kt
@@ -0,0 +1,9 @@
+package org.hyperskill.app.features.data.source
+
+import org.hyperskill.app.profile.domain.model.FeatureValues
+import org.hyperskill.app.profile.domain.model.FeaturesMap
+
+interface FeaturesDataSource {
+ fun getFeaturesMap(): FeaturesMap
+ fun getFeatureValues(): FeatureValues
+}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/injection/GamificationToolbarComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/injection/GamificationToolbarComponentImpl.kt
index 437511325e..395b95d6e3 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/injection/GamificationToolbarComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/injection/GamificationToolbarComponentImpl.kt
@@ -24,9 +24,8 @@ internal class GamificationToolbarComponentImpl(
topicCompletedFlow = appGraph.stepCompletionFlowDataComponent.topicCompletedFlow,
currentGamificationToolbarDataStateRepository = appGraph.stateRepositoriesComponent
.currentGamificationToolbarDataStateRepository,
- currentSubscriptionStateRepository = appGraph.stateRepositoriesComponent.currentSubscriptionStateRepository,
+ subscriptionInteractor = appGraph.subscriptionDataComponent.subscriptionsInteractor,
currentProfileStateRepository = appGraph.profileDataComponent.currentProfileStateRepository,
- purchaseInteractor = appGraph.buildPurchaseComponent().purchaseInteractor,
sentryInteractor = appGraph.sentryComponent.sentryInteractor
)
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarFeature.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarFeature.kt
index f417290476..33ef64e81b 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarFeature.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarFeature.kt
@@ -10,6 +10,8 @@ import org.hyperskill.app.streaks.domain.model.Streak
import org.hyperskill.app.study_plan.domain.model.StudyPlan
import org.hyperskill.app.subscriptions.domain.model.FreemiumChargeLimitsStrategy
import org.hyperskill.app.subscriptions.domain.model.Subscription
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionWithLimitType
object GamificationToolbarFeature {
sealed interface State {
@@ -22,8 +24,7 @@ object GamificationToolbarFeature {
val historicalStreak: HistoricalStreak,
val subscription: Subscription,
val chargeLimitsStrategy: FreemiumChargeLimitsStrategy,
- internal val isMobileContentTrialEnabled: Boolean,
- internal val canMakePayments: Boolean = false,
+ internal val subscriptionLimitType: SubscriptionLimitType,
internal val isRefreshing: Boolean = false
) : State
}
@@ -72,9 +73,8 @@ object GamificationToolbarFeature {
data class FetchGamificationToolbarDataSuccess(
val gamificationToolbarData: GamificationToolbarData,
val subscription: Subscription,
- val chargeLimitsStrategy: FreemiumChargeLimitsStrategy,
- val isMobileContentTrialEnabled: Boolean,
- val canMakePayments: Boolean
+ val subscriptionLimitType: SubscriptionLimitType,
+ val chargeLimitsStrategy: FreemiumChargeLimitsStrategy
) : InternalMessage
object PullToRefresh : InternalMessage
@@ -89,7 +89,9 @@ object GamificationToolbarFeature {
data class GamificationToolbarDataChanged(
val gamificationToolbarData: GamificationToolbarData
) : InternalMessage
- data class SubscriptionChanged(val subscription: Subscription) : InternalMessage
+ data class SubscriptionChanged(
+ val subscriptionWithLimitType: SubscriptionWithLimitType
+ ) : InternalMessage
}
sealed interface Action {
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarReducer.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarReducer.kt
index 9aaa4ef373..94e203ab28 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarReducer.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarReducer.kt
@@ -16,6 +16,7 @@ import org.hyperskill.app.streaks.domain.model.HistoricalStreak
import org.hyperskill.app.streaks.domain.model.StreakState
import org.hyperskill.app.subscriptions.domain.model.FreemiumChargeLimitsStrategy
import org.hyperskill.app.subscriptions.domain.model.Subscription
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
import ru.nobird.app.presentation.redux.reducer.StateReducer
private typealias GamificationToolbarReducerResult = Pair>
@@ -33,9 +34,8 @@ class GamificationToolbarReducer(
createContentState(
gamificationToolbarData = message.gamificationToolbarData,
subscription = message.subscription,
- chargeLimitsStrategy = message.chargeLimitsStrategy,
- isMobileContentTrialEnabled = message.isMobileContentTrialEnabled,
- canMakePayments = message.canMakePayments
+ subscriptionLimitType = message.subscriptionLimitType,
+ chargeLimitsStrategy = message.chargeLimitsStrategy
) to emptySet()
is InternalMessage.PullToRefresh ->
handlePullToRefreshMessage(state)
@@ -99,7 +99,10 @@ class GamificationToolbarReducer(
if (state.isRefreshing) {
state to emptySet()
} else {
- state.copy(subscription = message.subscription) to emptySet()
+ state.copy(
+ subscription = message.subscriptionWithLimitType.subscription,
+ subscriptionLimitType = message.subscriptionWithLimitType.subscriptionLimitType
+ ) to emptySet()
}
else -> state to emptySet()
}
@@ -226,9 +229,8 @@ class GamificationToolbarReducer(
private fun createContentState(
gamificationToolbarData: GamificationToolbarData,
subscription: Subscription,
- chargeLimitsStrategy: FreemiumChargeLimitsStrategy,
- isMobileContentTrialEnabled: Boolean,
- canMakePayments: Boolean
+ subscriptionLimitType: SubscriptionLimitType,
+ chargeLimitsStrategy: FreemiumChargeLimitsStrategy
): State.Content =
State.Content(
trackProgress = gamificationToolbarData.trackProgress,
@@ -236,7 +238,6 @@ class GamificationToolbarReducer(
historicalStreak = HistoricalStreak(gamificationToolbarData.streakState),
subscription = subscription,
chargeLimitsStrategy = chargeLimitsStrategy,
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
+ subscriptionLimitType = subscriptionLimitType
)
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/MainGamificationToolbarActionDispatcher.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/MainGamificationToolbarActionDispatcher.kt
index 3ac1e38eb0..255adbe5e2 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/MainGamificationToolbarActionDispatcher.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/MainGamificationToolbarActionDispatcher.kt
@@ -4,7 +4,6 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import org.hyperskill.app.core.domain.DataSourceType
import org.hyperskill.app.core.presentation.ActionDispatcherOptions
@@ -14,18 +13,15 @@ import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarF
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature.InternalMessage
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature.Message
import org.hyperskill.app.profile.domain.model.freemiumChargeLimitsStrategy
-import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
-import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.sentry.domain.withTransaction
import org.hyperskill.app.step_completion.domain.flow.StepCompletedFlow
import org.hyperskill.app.step_completion.domain.flow.TopicCompletedFlow
import org.hyperskill.app.streaks.domain.flow.StreakFlow
import org.hyperskill.app.study_plan.domain.repository.CurrentStudyPlanStateRepository
-import org.hyperskill.app.subscriptions.domain.model.Subscription
-import org.hyperskill.app.subscriptions.domain.model.orContentTrial
-import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
+import org.hyperskill.app.subscriptions.domain.interactor.SubscriptionsInteractor
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionWithLimitType
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher
internal class MainGamificationToolbarActionDispatcher(
@@ -35,14 +31,11 @@ internal class MainGamificationToolbarActionDispatcher(
currentStudyPlanStateRepository: CurrentStudyPlanStateRepository,
topicCompletedFlow: TopicCompletedFlow,
private val currentGamificationToolbarDataStateRepository: CurrentGamificationToolbarDataStateRepository,
- private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
private val currentProfileStateRepository: CurrentProfileStateRepository,
- private val purchaseInteractor: PurchaseInteractor,
+ private val subscriptionInteractor: SubscriptionsInteractor,
private val sentryInteractor: SentryInteractor
) : CoroutineActionDispatcher(config.createConfig()) {
- private var isMobileContentTrialEnabled: Boolean = false
-
init {
stepCompletedFlow.observe()
.onEach { onNewMessage(InternalMessage.StepSolved) }
@@ -74,13 +67,8 @@ internal class MainGamificationToolbarActionDispatcher(
.onEach { onNewMessage(InternalMessage.GamificationToolbarDataChanged(it)) }
.launchIn(actionScope)
- currentSubscriptionStateRepository.changes
- .map {
- it.orContentTrial(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments()
- )
- }
+ subscriptionInteractor
+ .subscribeOnSubscriptionWithLimitType()
.distinctUntilChanged()
.onEach { onNewMessage(InternalMessage.SubscriptionChanged(it)) }
.launchIn(actionScope)
@@ -117,46 +105,28 @@ internal class MainGamificationToolbarActionDispatcher(
val gamificationToolbarDataWithSource = toolbarDataDeferred.await().getOrThrow()
val profile = profileDeferred.await().getOrThrow()
- this@MainGamificationToolbarActionDispatcher.isMobileContentTrialEnabled =
- profile.features.isMobileContentTrialEnabled
-
- val canMakePayments = canMakePayments()
-
- val subscription = getSubscription(
- isMobileContentTrialEnabled = profile.features.isMobileContentTrialEnabled,
- canMakePayments = canMakePayments,
+ val subscriptionWithLimitType = getSubscription(
forceUpdate = action.forceUpdate,
gamificationToolbarDataSourceType = gamificationToolbarDataWithSource.usedDataSourceType
)
InternalMessage.FetchGamificationToolbarDataSuccess(
gamificationToolbarData = gamificationToolbarDataWithSource.state,
- subscription = subscription,
+ subscription = subscriptionWithLimitType.subscription,
+ subscriptionLimitType = subscriptionWithLimitType.subscriptionLimitType,
chargeLimitsStrategy = profile.freemiumChargeLimitsStrategy,
- isMobileContentTrialEnabled = profile.features.isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
)
}
}.let(onNewMessage)
}
private suspend fun getSubscription(
- isMobileContentTrialEnabled: Boolean,
- canMakePayments: Boolean,
forceUpdate: Boolean,
gamificationToolbarDataSourceType: DataSourceType
- ): Subscription {
+ ): SubscriptionWithLimitType {
val subscriptionWithSource =
- currentSubscriptionStateRepository
- .getStateWithSource(forceUpdate = forceUpdate)
- .map {
- it.copy(
- state = it.state.orContentTrial(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- )
- }
+ subscriptionInteractor
+ .getSubscriptionWithLimitTypeWithSource(forceUpdate = forceUpdate)
.getOrThrow()
// Fetch subscription from remote
@@ -168,20 +138,11 @@ internal class MainGamificationToolbarActionDispatcher(
subscriptionWithSource.usedDataSourceType == DataSourceType.CACHE
return if (shouldFetchSubscriptionFromRemote) {
- currentSubscriptionStateRepository
- .getState(forceUpdate = true)
- .map { subscription ->
- subscription.orContentTrial(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- }
+ subscriptionInteractor
+ .getSubscriptionWithLimitType(forceUpdate = true)
.getOrThrow()
} else {
subscriptionWithSource.state
}
}
-
- private suspend fun canMakePayments(): Boolean =
- purchaseInteractor.canMakePayments().getOrDefault(false)
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/view/mapper/GamificationToolbarViewStateMapper.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/view/mapper/GamificationToolbarViewStateMapper.kt
index fa6c327d5d..f81d53d4bc 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/view/mapper/GamificationToolbarViewStateMapper.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/view/mapper/GamificationToolbarViewStateMapper.kt
@@ -5,7 +5,6 @@ import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarF
import org.hyperskill.app.streaks.domain.model.StreakState
import org.hyperskill.app.subscriptions.domain.model.Subscription
import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
-import org.hyperskill.app.subscriptions.domain.model.getSubscriptionLimitType
internal object GamificationToolbarViewStateMapper {
fun map(state: GamificationToolbarFeature.State): GamificationToolbarFeature.ViewState =
@@ -28,8 +27,7 @@ internal object GamificationToolbarViewStateMapper {
),
problemsLimit = getProblemsLimitState(
subscription = state.subscription,
- isMobileContentTrialEnabled = state.isMobileContentTrialEnabled,
- canMakePayments = state.canMakePayments
+ subscriptionLimitType = state.subscriptionLimitType
)
)
@@ -48,14 +46,9 @@ internal object GamificationToolbarViewStateMapper {
private fun getProblemsLimitState(
subscription: Subscription,
- isMobileContentTrialEnabled: Boolean,
- canMakePayments: Boolean
+ subscriptionLimitType: SubscriptionLimitType
): GamificationToolbarFeature.ViewState.Content.ProblemsLimit? {
val stepsLimitLeft = subscription.stepsLimitLeft
- val subscriptionLimitType = subscription.getSubscriptionLimitType(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
return if (subscriptionLimitType == SubscriptionLimitType.PROBLEMS && stepsLimitLeft != null) {
GamificationToolbarFeature.ViewState.Content.ProblemsLimit(limitLabel = stepsLimitLeft.toString())
} else {
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/home/injection/HomeComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/home/injection/HomeComponentImpl.kt
index f13cba0810..a58c6ed3df 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/home/injection/HomeComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/home/injection/HomeComponentImpl.kt
@@ -19,14 +19,13 @@ internal class HomeComponentImpl(private val appGraph: AppGraph) : HomeComponent
currentProfileStateRepository = appGraph.profileDataComponent.currentProfileStateRepository,
topicsRepetitionsInteractor = appGraph.buildTopicsRepetitionsDataComponent().topicsRepetitionsInteractor,
stepInteractor = appGraph.buildStepDataComponent().stepInteractor,
- currentSubscriptionStateRepository = appGraph.stateRepositoriesComponent.currentSubscriptionStateRepository,
+ subscriptionsInteractor = appGraph.subscriptionDataComponent.subscriptionsInteractor,
analyticInteractor = appGraph.analyticComponent.analyticInteractor,
sentryInteractor = appGraph.sentryComponent.sentryInteractor,
dateFormatter = appGraph.commonComponent.dateFormatter,
topicRepeatedFlow = appGraph.topicsRepetitionsFlowDataComponent.topicRepeatedFlow,
topicCompletedFlow = appGraph.stepCompletionFlowDataComponent.topicCompletedFlow,
stepCompletedFlow = appGraph.stepCompletionFlowDataComponent.stepCompletedFlow,
- purchaseInteractor = appGraph.buildPurchaseComponent().purchaseInteractor,
gamificationToolbarReducer = gamificationToolbarComponent.gamificationToolbarReducer,
gamificationToolbarActionDispatcher = gamificationToolbarComponent.gamificationToolbarActionDispatcher,
challengeWidgetReducer = challengeWidgetComponent.challengeWidgetReducer,
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/home/injection/HomeFeatureBuilder.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/home/injection/HomeFeatureBuilder.kt
index 92dce97f53..53d4069ea4 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/home/injection/HomeFeatureBuilder.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/home/injection/HomeFeatureBuilder.kt
@@ -20,12 +20,11 @@ import org.hyperskill.app.home.presentation.HomeReducer
import org.hyperskill.app.home.view.mapper.HomeViewStateMapper
import org.hyperskill.app.logging.presentation.wrapWithLogger
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
-import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.step.domain.interactor.StepInteractor
import org.hyperskill.app.step_completion.domain.flow.StepCompletedFlow
import org.hyperskill.app.step_completion.domain.flow.TopicCompletedFlow
-import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
+import org.hyperskill.app.subscriptions.domain.interactor.SubscriptionsInteractor
import org.hyperskill.app.topics_repetitions.domain.flow.TopicRepeatedFlow
import org.hyperskill.app.topics_repetitions.domain.interactor.TopicsRepetitionsInteractor
import ru.nobird.app.core.model.safeCast
@@ -41,14 +40,13 @@ internal object HomeFeatureBuilder {
currentProfileStateRepository: CurrentProfileStateRepository,
topicsRepetitionsInteractor: TopicsRepetitionsInteractor,
stepInteractor: StepInteractor,
- currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
+ subscriptionsInteractor: SubscriptionsInteractor,
analyticInteractor: AnalyticInteractor,
sentryInteractor: SentryInteractor,
dateFormatter: SharedDateFormatter,
topicRepeatedFlow: TopicRepeatedFlow,
topicCompletedFlow: TopicCompletedFlow,
stepCompletedFlow: StepCompletedFlow,
- purchaseInteractor: PurchaseInteractor,
gamificationToolbarReducer: GamificationToolbarReducer,
gamificationToolbarActionDispatcher: GamificationToolbarActionDispatcher,
challengeWidgetReducer: ChallengeWidgetReducer,
@@ -66,13 +64,12 @@ internal object HomeFeatureBuilder {
currentProfileStateRepository = currentProfileStateRepository,
topicsRepetitionsInteractor = topicsRepetitionsInteractor,
stepInteractor = stepInteractor,
- currentSubscriptionStateRepository = currentSubscriptionStateRepository,
sentryInteractor = sentryInteractor,
- purchaseInteractor = purchaseInteractor,
dateFormatter = dateFormatter,
topicRepeatedFlow = topicRepeatedFlow,
topicCompletedFlow = topicCompletedFlow,
- stepCompletedFlow = stepCompletedFlow
+ stepCompletedFlow = stepCompletedFlow,
+ subscriptionInteractor = subscriptionsInteractor
)
val homeViewStateMapper = HomeViewStateMapper(
challengeWidgetViewStateMapper = challengeWidgetViewStateMapper
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeActionDispatcher.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeActionDispatcher.kt
index 18968819a5..e1a5a2bcaa 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeActionDispatcher.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeActionDispatcher.kt
@@ -16,17 +16,14 @@ import org.hyperskill.app.home.presentation.HomeFeature.Action
import org.hyperskill.app.home.presentation.HomeFeature.InternalAction
import org.hyperskill.app.home.presentation.HomeFeature.InternalMessage
import org.hyperskill.app.home.presentation.HomeFeature.Message
-import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
-import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.sentry.domain.model.transaction.HyperskillSentryTransactionBuilder
import org.hyperskill.app.sentry.domain.withTransaction
import org.hyperskill.app.step.domain.interactor.StepInteractor
import org.hyperskill.app.step_completion.domain.flow.StepCompletedFlow
import org.hyperskill.app.step_completion.domain.flow.TopicCompletedFlow
-import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
-import org.hyperskill.app.subscriptions.domain.repository.areProblemsLimited
+import org.hyperskill.app.subscriptions.domain.interactor.SubscriptionsInteractor
import org.hyperskill.app.topics_repetitions.domain.flow.TopicRepeatedFlow
import org.hyperskill.app.topics_repetitions.domain.interactor.TopicsRepetitionsInteractor
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher
@@ -36,9 +33,8 @@ internal class HomeActionDispatcher(
private val currentProfileStateRepository: CurrentProfileStateRepository,
private val topicsRepetitionsInteractor: TopicsRepetitionsInteractor,
private val stepInteractor: StepInteractor,
- private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
+ private val subscriptionInteractor: SubscriptionsInteractor,
private val sentryInteractor: SentryInteractor,
- private val purchaseInteractor: PurchaseInteractor,
private val dateFormatter: SharedDateFormatter,
topicRepeatedFlow: TopicRepeatedFlow,
topicCompletedFlow: TopicCompletedFlow,
@@ -115,18 +111,15 @@ internal class HomeActionDispatcher(
val problemOfDayStateResult = async { getProblemOfDayState(currentProfile.dailyStep) }
val repetitionsStateResult = async { getRepetitionsState() }
- val areProblemsLimited = async {
- currentSubscriptionStateRepository.areProblemsLimited(
- isMobileContentTrialEnabled = currentProfile.features.isMobileContentTrialEnabled,
- canMakePayments = purchaseInteractor.canMakePayments().getOrDefault(false)
- )
+ val isProblemsLimitEnabled = async {
+ subscriptionInteractor.isProblemsLimitEnabled()
}
setOf(
Message.HomeSuccess(
problemOfDayState = problemOfDayStateResult.await().getOrThrow(),
repetitionsState = repetitionsStateResult.await().getOrThrow(),
- areProblemsLimited = areProblemsLimited.await()
+ isProblemsLimitEnabled = isProblemsLimitEnabled.await()
),
Message.ReadyToLaunchNextProblemInTimer
)
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeFeature.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeFeature.kt
index ee33d6bb0a..80598355cc 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeFeature.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeFeature.kt
@@ -45,7 +45,7 @@ object HomeFeature {
*
* @property problemOfDayState Problem of the day state.
* @property repetitionsState Topics repetitions state.
- * @property areProblemsLimited A boolean flag that indicates that problem limits are enabled.
+ * @property isProblemsLimitEnabled A boolean flag that indicates that problem limits are enabled.
* @property isRefreshing A boolean flag that indicates about is pull-to-refresh is ongoing.
*
* @see Streak
@@ -54,7 +54,7 @@ object HomeFeature {
data class Content(
val problemOfDayState: ProblemOfDayState,
val repetitionsState: RepetitionsState,
- val areProblemsLimited: Boolean,
+ val isProblemsLimitEnabled: Boolean,
internal val isRefreshing: Boolean = false
) : HomeState
@@ -105,7 +105,7 @@ object HomeFeature {
data class HomeSuccess(
val problemOfDayState: ProblemOfDayState,
val repetitionsState: RepetitionsState,
- val areProblemsLimited: Boolean
+ val isProblemsLimitEnabled: Boolean
) : Message
object HomeFailure : Message
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeReducer.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeReducer.kt
index 2b811c148c..be19adf5d7 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeReducer.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/home/presentation/HomeReducer.kt
@@ -34,7 +34,7 @@ internal class HomeReducer(
homeState = HomeState.Content(
problemOfDayState = message.problemOfDayState,
repetitionsState = message.repetitionsState,
- areProblemsLimited = message.areProblemsLimited
+ isProblemsLimitEnabled = message.isProblemsLimitEnabled
)
) to emptySet()
}
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/main/presentation/AppActionDispatcher.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/main/presentation/AppActionDispatcher.kt
index eaca07e549..96eac4f53d 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/main/presentation/AppActionDispatcher.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/main/presentation/AppActionDispatcher.kt
@@ -5,7 +5,6 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import org.hyperskill.app.auth.domain.interactor.AuthInteractor
import org.hyperskill.app.auth.domain.model.UserDeauthorized
@@ -19,7 +18,6 @@ import org.hyperskill.app.main.presentation.AppFeature.InternalMessage
import org.hyperskill.app.main.presentation.AppFeature.Message
import org.hyperskill.app.notification.local.domain.interactor.NotificationInteractor
import org.hyperskill.app.notification.remote.domain.interactor.PushNotificationsInteractor
-import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.sentry.domain.model.breadcrumb.HyperskillSentryBreadcrumbBuilder
@@ -30,7 +28,6 @@ import org.hyperskill.app.subscriptions.domain.model.Subscription
import org.hyperskill.app.subscriptions.domain.model.SubscriptionType
import org.hyperskill.app.subscriptions.domain.model.isExpired
import org.hyperskill.app.subscriptions.domain.model.isValidTillPassed
-import org.hyperskill.app.subscriptions.domain.model.orContentTrial
import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher
@@ -48,8 +45,6 @@ internal class AppActionDispatcher(
private val logger: Logger
) : CoroutineActionDispatcher(config.createConfig()) {
- private var isMobileContentTrialEnabled: Boolean = false
-
init {
authInteractor
.observeUserDeauthorization()
@@ -73,12 +68,6 @@ internal class AppActionDispatcher(
currentSubscriptionStateRepository
.changes
- .map {
- it.orContentTrial(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments()
- )
- }
.distinctUntilChanged()
.onEach { subscription ->
onNewMessage(InternalMessage.SubscriptionChanged(subscription))
@@ -138,8 +127,6 @@ internal class AppActionDispatcher(
val profile = profileDeferred.await().getOrThrow()
- this@AppActionDispatcher.isMobileContentTrialEnabled = profile.features.isMobileContentTrialEnabled
-
val subscription = subscriptionDeferred.await()
val canMakePayments = if (isAuthorized) {
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/profile/cache/CurrentProfileStateHolderImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/profile/cache/CurrentProfileStateHolderImpl.kt
index 8bb316fd52..866e15cc0e 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/profile/cache/CurrentProfileStateHolderImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/profile/cache/CurrentProfileStateHolderImpl.kt
@@ -2,17 +2,23 @@ package org.hyperskill.app.profile.cache
import com.russhwolf.settings.Settings
import kotlinx.serialization.json.Json
+import org.hyperskill.app.features.data.source.FeaturesDataSource
import org.hyperskill.app.profile.data.source.CurrentProfileStateHolder
+import org.hyperskill.app.profile.domain.model.FeatureValues
+import org.hyperskill.app.profile.domain.model.FeaturesMap
import org.hyperskill.app.profile.domain.model.Profile
class CurrentProfileStateHolderImpl(
private val json: Json,
private val settings: Settings
-) : CurrentProfileStateHolder {
+) : CurrentProfileStateHolder, FeaturesDataSource {
private var cachedProfile: Profile? = null
- override suspend fun getState(): Profile? {
+ override suspend fun getState(): Profile? =
+ getStateInternal()
+
+ private fun getStateInternal(): Profile? {
if (cachedProfile == null) {
cachedProfile = readProfileFromSettings()
}
@@ -55,4 +61,10 @@ class CurrentProfileStateHolderImpl(
settings.remove(ProfileCacheKeyValues.GUEST_PROFILE)
settings.remove(ProfileCacheKeyValues.CURRENT_PROFILE)
}
+
+ override fun getFeaturesMap(): FeaturesMap =
+ getStateInternal()?.features ?: FeaturesMap(emptyMap())
+
+ override fun getFeatureValues(): FeatureValues =
+ getStateInternal()?.featureValues ?: FeatureValues()
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/profile/domain/model/FeaturesMap.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/profile/domain/model/FeaturesMap.kt
index 11ce0534ea..2009058866 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/profile/domain/model/FeaturesMap.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/profile/domain/model/FeaturesMap.kt
@@ -1,5 +1,7 @@
package org.hyperskill.app.profile.domain.model
+import org.hyperskill.app.subscriptions.domain.model.FreemiumChargeLimitsStrategy
+
data class FeaturesMap(internal val origin: Map) : Map by origin
val FeaturesMap.isRecommendationsJavaProjectsFeatureEnabled: Boolean
@@ -17,6 +19,13 @@ val FeaturesMap.isFreemiumIncreaseLimitsForFirstStepCompletionEnabled: Boolean
val FeaturesMap.isFreemiumWrongSubmissionChargeLimitsEnabled: Boolean
get() = get(FeatureKeys.FREEMIUM_WRONG_SUBMISSION_CHARGE_LIMITS) ?: false
+internal val FeaturesMap.freemiumChargeLimitsStrategy: FreemiumChargeLimitsStrategy
+ get() = if (isFreemiumWrongSubmissionChargeLimitsEnabled) {
+ FreemiumChargeLimitsStrategy.AFTER_WRONG_SUBMISSION
+ } else {
+ FreemiumChargeLimitsStrategy.AFTER_CORRECT_SUBMISSION
+ }
+
val FeaturesMap.isLearningPathDividedTrackTopicsEnabled: Boolean
get() = get(FeatureKeys.LEARNING_PATH_DIVIDED_TRACK_TOPICS) ?: false
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/profile/injection/ProfileDataComponent.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/profile/injection/ProfileDataComponent.kt
index 2a81198105..f3ffae23ea 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/profile/injection/ProfileDataComponent.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/profile/injection/ProfileDataComponent.kt
@@ -1,9 +1,11 @@
package org.hyperskill.app.profile.injection
+import org.hyperskill.app.features.data.source.FeaturesDataSource
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
import org.hyperskill.app.profile.domain.repository.ProfileRepository
interface ProfileDataComponent {
val profileRepository: ProfileRepository
val currentProfileStateRepository: CurrentProfileStateRepository
+ val featuresDataSource: FeaturesDataSource
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/profile/injection/ProfileDataComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/profile/injection/ProfileDataComponentImpl.kt
index 965bae52cd..5a9885f9ad 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/profile/injection/ProfileDataComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/profile/injection/ProfileDataComponentImpl.kt
@@ -1,11 +1,11 @@
package org.hyperskill.app.profile.injection
import org.hyperskill.app.core.injection.CommonComponent
+import org.hyperskill.app.features.data.source.FeaturesDataSource
import org.hyperskill.app.network.injection.NetworkComponent
import org.hyperskill.app.profile.cache.CurrentProfileStateHolderImpl
import org.hyperskill.app.profile.data.repository.CurrentProfileStateRepositoryImpl
import org.hyperskill.app.profile.data.repository.ProfileRepositoryImpl
-import org.hyperskill.app.profile.data.source.CurrentProfileStateHolder
import org.hyperskill.app.profile.data.source.ProfileRemoteDataSource
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
import org.hyperskill.app.profile.domain.repository.ProfileRepository
@@ -22,7 +22,7 @@ internal class ProfileDataComponentImpl(
)
}
- private val currentProfileStateHolder: CurrentProfileStateHolder by lazy {
+ private val currentProfileStateHolder by lazy {
CurrentProfileStateHolderImpl(
commonComponent.json,
commonComponent.settings
@@ -38,4 +38,7 @@ internal class ProfileDataComponentImpl(
stateHolder = currentProfileStateHolder
)
}
+
+ override val featuresDataSource: FeaturesDataSource
+ get() = currentProfileStateHolder
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/injection/StepCompletionComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/injection/StepCompletionComponentImpl.kt
index beb7133046..27ca661827 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/injection/StepCompletionComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/injection/StepCompletionComponentImpl.kt
@@ -34,9 +34,7 @@ internal class StepCompletionComponentImpl(
.currentGamificationToolbarDataStateRepository,
dailyStepCompletedFlow = appGraph.stepCompletionFlowDataComponent.dailyStepCompletedFlow,
topicCompletedFlow = appGraph.stepCompletionFlowDataComponent.topicCompletedFlow,
- topicProgressFlow = appGraph.progressesFlowDataComponent.topicProgressFlow,
- purchaseInteractor = appGraph.buildPurchaseComponent().purchaseInteractor,
- currentSubscriptionStateRepository = appGraph.stateRepositoriesComponent.currentSubscriptionStateRepository
+ topicProgressFlow = appGraph.progressesFlowDataComponent.topicProgressFlow
)
override val stepCompletionActionDispatcher: StepCompletionActionDispatcher
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/presentation/MainStepCompletionActionDispatcher.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/presentation/MainStepCompletionActionDispatcher.kt
index e2666c99cd..0deb04f3fd 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/presentation/MainStepCompletionActionDispatcher.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/presentation/MainStepCompletionActionDispatcher.kt
@@ -10,11 +10,9 @@ import org.hyperskill.app.core.presentation.ActionDispatcherOptions
import org.hyperskill.app.core.view.mapper.ResourceProvider
import org.hyperskill.app.gamification_toolbar.domain.repository.CurrentGamificationToolbarDataStateRepository
import org.hyperskill.app.learning_activities.domain.repository.NextLearningActivityStateRepository
-import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
import org.hyperskill.app.progresses.domain.flow.TopicProgressFlow
import org.hyperskill.app.progresses.domain.interactor.ProgressesInteractor
-import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.request_review.domain.interactor.RequestReviewInteractor
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.sentry.domain.model.transaction.HyperskillSentryTransactionBuilder
@@ -37,9 +35,6 @@ import org.hyperskill.app.step_completion.presentation.StepCompletionFeature.Mes
import org.hyperskill.app.streaks.domain.model.StreakState
import org.hyperskill.app.subscriptions.domain.interactor.SubscriptionsInteractor
import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
-import org.hyperskill.app.subscriptions.domain.model.getSubscriptionLimitType
-import org.hyperskill.app.subscriptions.domain.model.orContentTrial
-import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
import org.hyperskill.app.topics.domain.repository.TopicsRepository
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher
@@ -60,9 +55,7 @@ internal class MainStepCompletionActionDispatcher(
private val currentGamificationToolbarDataStateRepository: CurrentGamificationToolbarDataStateRepository,
private val dailyStepCompletedFlow: DailyStepCompletedFlow,
private val topicCompletedFlow: TopicCompletedFlow,
- private val topicProgressFlow: TopicProgressFlow,
- private val purchaseInteractor: PurchaseInteractor,
- private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository
+ private val topicProgressFlow: TopicProgressFlow
) : CoroutineActionDispatcher(config.createConfig()) {
init {
@@ -168,7 +161,6 @@ internal class MainStepCompletionActionDispatcher(
val isTopicsLimitReached = isTopicsLimitReached(
trackId = trackId,
- isMobileContentTrialEnabled = profile.features.isMobileContentTrialEnabled,
mobileContentTrialFreeTopics = profile.featureValues.mobileContentTrialFreeTopics
)
@@ -197,21 +189,11 @@ internal class MainStepCompletionActionDispatcher(
private suspend fun isTopicsLimitReached(
trackId: Long,
- isMobileContentTrialEnabled: Boolean,
mobileContentTrialFreeTopics: Int
): Boolean =
coroutineScope {
- val canMakePayments = purchaseInteractor.canMakePayments().getOrDefault(false)
-
- val subscriptionDeferred = async {
- currentSubscriptionStateRepository
- .getState(forceUpdate = true)
- .map { subscription ->
- subscription.orContentTrial(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- }
+ val subscriptionWithLimitTypeDeferred = async {
+ subscriptionsInteractor.getSubscriptionLimitType(forceUpdate = true)
}
val trackProgressDeferred = async {
progressesInteractor
@@ -221,14 +203,9 @@ internal class MainStepCompletionActionDispatcher(
)
}
- val subscription = subscriptionDeferred.await().getOrThrow()
+ val subscriptionLimitType = subscriptionWithLimitTypeDeferred.await().getOrThrow()
val trackProgress = requireNotNull(trackProgressDeferred.await().getOrThrow())
- val subscriptionLimitType = subscription.getSubscriptionLimitType(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
-
subscriptionLimitType == SubscriptionLimitType.TOPICS &&
trackProgress.learnedTopicsCount >= mobileContentTrialFreeTopics
}
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/injection/StepQuizComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/injection/StepQuizComponentImpl.kt
index c2d226289e..cb7e315e64 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/injection/StepQuizComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/injection/StepQuizComponentImpl.kt
@@ -72,8 +72,7 @@ internal class StepQuizComponentImpl(
analyticInteractor = appGraph.analyticComponent.analyticInteractor,
sentryInteractor = appGraph.sentryComponent.sentryInteractor,
onboardingInteractor = appGraph.buildOnboardingDataComponent().onboardingInteractor,
- currentSubscriptionStateRepository = appGraph.stateRepositoriesComponent.currentSubscriptionStateRepository,
- purchaseInteractor = appGraph.buildPurchaseComponent().purchaseInteractor,
+ featuresDataSource = appGraph.profileDataComponent.featuresDataSource,
logger = appGraph.loggerComponent.logger,
buildVariant = appGraph.commonComponent.buildKonfig.buildVariant,
stepQuizHintsActionDispatcher = stepQuizHintsComponent.stepQuizHintsActionDispatcher,
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/injection/StepQuizFeatureBuilder.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/injection/StepQuizFeatureBuilder.kt
index 035ab1ca4c..5a15acdd09 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/injection/StepQuizFeatureBuilder.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/injection/StepQuizFeatureBuilder.kt
@@ -5,11 +5,11 @@ import org.hyperskill.app.analytic.domain.interactor.AnalyticInteractor
import org.hyperskill.app.analytic.presentation.wrapWithAnalyticLogger
import org.hyperskill.app.core.domain.BuildVariant
import org.hyperskill.app.core.presentation.ActionDispatcherOptions
+import org.hyperskill.app.features.data.source.FeaturesDataSource
import org.hyperskill.app.logging.presentation.wrapWithLogger
import org.hyperskill.app.magic_links.domain.interactor.UrlPathProcessor
import org.hyperskill.app.onboarding.domain.interactor.OnboardingInteractor
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
-import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.step.domain.model.StepRoute
import org.hyperskill.app.step_quiz.domain.interactor.StepQuizInteractor
@@ -28,7 +28,6 @@ import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarActionDi
import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarFeature
import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarReducer
import org.hyperskill.app.subscriptions.domain.interactor.SubscriptionsInteractor
-import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
import ru.nobird.app.core.model.safeCast
import ru.nobird.app.presentation.redux.dispatcher.transform
import ru.nobird.app.presentation.redux.dispatcher.wrapWithActionDispatcher
@@ -48,8 +47,7 @@ internal object StepQuizFeatureBuilder {
analyticInteractor: AnalyticInteractor,
sentryInteractor: SentryInteractor,
onboardingInteractor: OnboardingInteractor,
- currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
- purchaseInteractor: PurchaseInteractor,
+ featuresDataSource: FeaturesDataSource,
stepQuizHintsReducer: StepQuizHintsReducer,
stepQuizHintsActionDispatcher: StepQuizHintsActionDispatcher,
stepQuizToolbarReducer: StepQuizToolbarReducer,
@@ -74,12 +72,11 @@ internal object StepQuizFeatureBuilder {
stepQuizReplyValidator = stepQuizReplyValidator,
subscriptionsInteractor = subscriptionsInteractor,
currentProfileStateRepository = currentProfileStateRepository,
- currentSubscriptionStateRepository = currentSubscriptionStateRepository,
+ featuresDataSource = featuresDataSource,
urlPathProcessor = urlPathProcessor,
analyticInteractor = analyticInteractor,
sentryInteractor = sentryInteractor,
onboardingInteractor = onboardingInteractor,
- purchaseInteractor = purchaseInteractor,
logger = logger.withTag(LOG_TAG)
)
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/presentation/StepQuizActionDispatcher.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/presentation/StepQuizActionDispatcher.kt
index ee05934e22..de85daa87e 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/presentation/StepQuizActionDispatcher.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/presentation/StepQuizActionDispatcher.kt
@@ -3,19 +3,16 @@ package org.hyperskill.app.step_quiz.presentation
import co.touchlab.kermit.Logger
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.launch
import org.hyperskill.app.analytic.domain.interactor.AnalyticInteractor
import org.hyperskill.app.core.domain.url.HyperskillUrlPath
import org.hyperskill.app.core.presentation.ActionDispatcherOptions
+import org.hyperskill.app.features.data.source.FeaturesDataSource
import org.hyperskill.app.magic_links.domain.interactor.UrlPathProcessor
import org.hyperskill.app.onboarding.domain.interactor.OnboardingInteractor
import org.hyperskill.app.profile.domain.model.freemiumChargeLimitsStrategy
import org.hyperskill.app.profile.domain.model.isFreemiumWrongSubmissionChargeLimitsEnabled
-import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
-import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.sentry.domain.model.transaction.HyperskillSentryTransactionBuilder
import org.hyperskill.app.sentry.domain.withTransaction
@@ -32,8 +29,6 @@ import org.hyperskill.app.submissions.domain.model.SubmissionStatus
import org.hyperskill.app.submissions.domain.model.isWrongOrRejected
import org.hyperskill.app.subscriptions.domain.interactor.SubscriptionsInteractor
import org.hyperskill.app.subscriptions.domain.model.isProblemsLimitReached
-import org.hyperskill.app.subscriptions.domain.model.orContentTrial
-import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher
internal class StepQuizActionDispatcher(
@@ -41,44 +36,28 @@ internal class StepQuizActionDispatcher(
private val stepQuizInteractor: StepQuizInteractor,
private val stepQuizReplyValidator: StepQuizReplyValidator,
private val subscriptionsInteractor: SubscriptionsInteractor,
- private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
private val currentProfileStateRepository: CurrentProfileStateRepository,
+ private val featuresDataSource: FeaturesDataSource,
private val urlPathProcessor: UrlPathProcessor,
private val analyticInteractor: AnalyticInteractor,
private val sentryInteractor: SentryInteractor,
private val onboardingInteractor: OnboardingInteractor,
- private val purchaseInteractor: PurchaseInteractor,
private val logger: Logger
) : CoroutineActionDispatcher(config.createConfig()) {
init {
- actionScope.launch {
- val isMobileContentTrialEnabled = currentProfileStateRepository
- .getState()
- .map { it.features.isMobileContentTrialEnabled }
- .getOrDefault(false)
- currentSubscriptionStateRepository
- .changes
- .map { subscription ->
- val canMakePayments = canMakePayments()
- subscription to subscription
- .orContentTrial(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- .isProblemsLimitReached(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- }
- .distinctUntilChangedBy { (_, isProblemsLimitReached) -> isProblemsLimitReached }
- .onEach { (subscription, isProblemsLimitReached) ->
- onNewMessage(
- InternalMessage.ProblemsLimitChanged(subscription, isProblemsLimitReached)
+ subscriptionsInteractor
+ .subscribeOnSubscriptionWithLimitType()
+ .distinctUntilChangedBy { it.isProblemsLimitReached }
+ .onEach {
+ onNewMessage(
+ InternalMessage.ProblemsLimitChanged(
+ subscription = it.subscription,
+ isProblemsLimitReached = it.isProblemsLimitReached
)
- }
- .launchIn(this)
- }
+ )
+ }
+ .launchIn(actionScope)
}
override suspend fun doSuspendableAction(action: Action) {
@@ -238,18 +217,8 @@ internal class StepQuizActionDispatcher(
.getState()
.getOrThrow()
- val canMakePayments = canMakePayments()
-
- val currentSubscription =
- currentSubscriptionStateRepository
- .getState()
- .map { subscription ->
- subscription.orContentTrial(
- isMobileContentTrialEnabled = currentProfile.features.isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- }
- .getOrThrow()
+ val subscriptionWithLimitType =
+ subscriptionsInteractor.getSubscriptionWithLimitType().getOrThrow()
val attempt =
stepQuizInteractor
@@ -263,14 +232,10 @@ internal class StepQuizActionDispatcher(
step = action.step,
attempt = attempt,
submissionState = submissionState,
- subscription = currentSubscription,
+ subscription = subscriptionWithLimitType.subscription,
chargeLimitsStrategy = currentProfile.freemiumChargeLimitsStrategy,
problemsOnboardingFlags = onboardingInteractor.getProblemsOnboardingFlags(),
- isProblemsLimitReached = currentSubscription
- .isProblemsLimitReached(
- isMobileContentTrialEnabled = currentProfile.features.isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
+ isProblemsLimitReached = subscriptionWithLimitType.isProblemsLimitReached
)
}.let(onNewMessage)
}
@@ -294,37 +259,20 @@ internal class StepQuizActionDispatcher(
action: InternalAction.UpdateProblemsLimit,
onNewMessage: (Message) -> Unit
) {
- val currentProfile = currentProfileStateRepository.getState().getOrElse { return }
- if (!currentProfile.features.isFreemiumWrongSubmissionChargeLimitsEnabled) return
+ val features = featuresDataSource.getFeaturesMap()
+ if (!features.isFreemiumWrongSubmissionChargeLimitsEnabled) return
subscriptionsInteractor.chargeProblemsLimits(action.chargeStrategy)
- val canMakePayments = canMakePayments()
-
- val currentSubscription =
- currentSubscriptionStateRepository
- .getState()
- .map { subscription ->
- subscription.orContentTrial(
- isMobileContentTrialEnabled = currentProfile.features.isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- }
- .getOrElse { return }
+ val currentSubscriptionWithLimitType =
+ subscriptionsInteractor.getSubscriptionWithLimitType().getOrElse { return }
onNewMessage(
InternalMessage.UpdateProblemsLimitResult(
- subscription = currentSubscription,
- isProblemsLimitReached = currentSubscription
- .isProblemsLimitReached(
- isMobileContentTrialEnabled = currentProfile.features.isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- ),
- chargeLimitsStrategy = currentProfile.freemiumChargeLimitsStrategy
+ subscription = currentSubscriptionWithLimitType.subscription,
+ isProblemsLimitReached = currentSubscriptionWithLimitType.isProblemsLimitReached,
+ chargeLimitsStrategy = features.freemiumChargeLimitsStrategy
)
)
}
-
- private suspend fun canMakePayments(): Boolean =
- purchaseInteractor.canMakePayments().getOrDefault(false)
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/injection/StepQuizToolbarComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/injection/StepQuizToolbarComponentImpl.kt
index 877adef2f8..16b707b544 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/injection/StepQuizToolbarComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/injection/StepQuizToolbarComponentImpl.kt
@@ -22,9 +22,8 @@ internal class StepQuizToolbarComponentImpl(
private val mainStepQuizToolbarActionDispatcher: MainStepQuizToolbarActionDispatcher
get() = MainStepQuizToolbarActionDispatcher(
config = ActionDispatcherOptions(),
- currentSubscriptionStateRepository = appGraph.stateRepositoriesComponent.currentSubscriptionStateRepository,
- currentProfileStateRepository = appGraph.profileDataComponent.currentProfileStateRepository,
- purchaseInteractor = appGraph.buildPurchaseComponent().purchaseInteractor,
+ subscriptionsInteractor = appGraph.subscriptionDataComponent.subscriptionsInteractor,
+ featuresDataSource = appGraph.profileDataComponent.featuresDataSource,
logger = appGraph.loggerComponent.logger.withTag(LOG_TAG)
)
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/MainStepQuizToolbarActionDispatcher.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/MainStepQuizToolbarActionDispatcher.kt
index 262dbb31ac..72281c0a01 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/MainStepQuizToolbarActionDispatcher.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/MainStepQuizToolbarActionDispatcher.kt
@@ -3,40 +3,27 @@ package org.hyperskill.app.step_quiz_toolbar.presentation
import co.touchlab.kermit.Logger
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import org.hyperskill.app.core.presentation.ActionDispatcherOptions
+import org.hyperskill.app.features.data.source.FeaturesDataSource
import org.hyperskill.app.profile.domain.model.freemiumChargeLimitsStrategy
-import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
-import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
-import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarFeature.Action
import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarFeature.InternalAction
import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarFeature.InternalMessage
import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarFeature.Message
-import org.hyperskill.app.subscriptions.domain.model.orContentTrial
-import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
+import org.hyperskill.app.subscriptions.domain.interactor.SubscriptionsInteractor
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher
internal class MainStepQuizToolbarActionDispatcher(
config: ActionDispatcherOptions,
- private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
- private val currentProfileStateRepository: CurrentProfileStateRepository,
- private val purchaseInteractor: PurchaseInteractor,
+ private val subscriptionsInteractor: SubscriptionsInteractor,
+ private val featuresDataSource: FeaturesDataSource,
private val logger: Logger
) : CoroutineActionDispatcher(config.createConfig()) {
- private var isMobileContentTrialEnabled = false
-
init {
- currentSubscriptionStateRepository
- .changes
- .map { subscription ->
- subscription.orContentTrial(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments()
- )
- }
+ subscriptionsInteractor
+ .subscribeOnSubscriptionWithLimitType()
.distinctUntilChanged()
.onEach {
onNewMessage(InternalMessage.SubscriptionChanged(it))
@@ -54,39 +41,23 @@ internal class MainStepQuizToolbarActionDispatcher(
}
private suspend fun handleFetchSubscription(onNewMessage: (Message) -> Unit) {
- val profile = currentProfileStateRepository.getState().getOrElse {
- logger.e(it) { "Failed to fetch profile" }
- onNewMessage(InternalMessage.SubscriptionFetchError)
- return
- }
-
- this.isMobileContentTrialEnabled = profile.features.isMobileContentTrialEnabled
+ val features = featuresDataSource.getFeaturesMap()
- val canMakePayments = canMakePayments()
+ val subscriptionWithLimitType =
+ subscriptionsInteractor
+ .getSubscriptionWithLimitType()
+ .getOrElse {
+ logger.e(it) { "Failed to fetch subscription" }
+ onNewMessage(InternalMessage.SubscriptionFetchError)
+ return
+ }
- val subscription = currentSubscriptionStateRepository
- .getState()
- .map { subscription ->
- subscription.orContentTrial(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- }
- .getOrElse {
- logger.e(it) { "Failed to fetch subscription" }
- onNewMessage(InternalMessage.SubscriptionFetchError)
- return
- }
onNewMessage(
InternalMessage.SubscriptionFetchSuccess(
- subscription = subscription,
- isMobileContentTrialEnabled = profile.features.isMobileContentTrialEnabled,
- canMakePayment = canMakePayments,
- chargeLimitsStrategy = profile.freemiumChargeLimitsStrategy
+ subscription = subscriptionWithLimitType.subscription,
+ subscriptionLimitType = subscriptionWithLimitType.subscriptionLimitType,
+ chargeLimitsStrategy = features.freemiumChargeLimitsStrategy
)
)
}
-
- private suspend fun canMakePayments(): Boolean =
- purchaseInteractor.canMakePayments().getOrDefault(false)
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/StepQuizToolbarFeature.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/StepQuizToolbarFeature.kt
index aec77bf891..ff78f8948b 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/StepQuizToolbarFeature.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/StepQuizToolbarFeature.kt
@@ -5,6 +5,8 @@ import org.hyperskill.app.problems_limit_info.domain.model.ProblemsLimitInfoModa
import org.hyperskill.app.step.domain.model.StepRoute
import org.hyperskill.app.subscriptions.domain.model.FreemiumChargeLimitsStrategy
import org.hyperskill.app.subscriptions.domain.model.Subscription
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionWithLimitType
object StepQuizToolbarFeature {
sealed interface State {
@@ -14,8 +16,7 @@ object StepQuizToolbarFeature {
object Error : State
data class Content(
val subscription: Subscription,
- val isMobileContentTrialEnabled: Boolean,
- val canMakePayment: Boolean,
+ val subscriptionLimitType: SubscriptionLimitType,
val chargeLimitsStrategy: FreemiumChargeLimitsStrategy
) : State
}
@@ -47,12 +48,13 @@ object StepQuizToolbarFeature {
object SubscriptionFetchError : InternalMessage
data class SubscriptionFetchSuccess(
val subscription: Subscription,
- val isMobileContentTrialEnabled: Boolean,
- val canMakePayment: Boolean,
+ val subscriptionLimitType: SubscriptionLimitType,
val chargeLimitsStrategy: FreemiumChargeLimitsStrategy
) : InternalMessage
- data class SubscriptionChanged(val subscription: Subscription) : InternalMessage
+ data class SubscriptionChanged(
+ val subscriptionWithLimitType: SubscriptionWithLimitType
+ ) : InternalMessage
}
sealed interface Action {
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/StepQuizToolbarReducer.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/StepQuizToolbarReducer.kt
index 92a4b82590..47ef21cb39 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/StepQuizToolbarReducer.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/presentation/StepQuizToolbarReducer.kt
@@ -40,8 +40,7 @@ class StepQuizToolbarReducer(
): StepQuizToolbarReducerResult =
State.Content(
subscription = message.subscription,
- isMobileContentTrialEnabled = message.isMobileContentTrialEnabled,
- canMakePayment = message.canMakePayment,
+ subscriptionLimitType = message.subscriptionLimitType,
chargeLimitsStrategy = message.chargeLimitsStrategy
) to emptySet()
@@ -53,7 +52,10 @@ class StepQuizToolbarReducer(
message: InternalMessage.SubscriptionChanged
): StepQuizToolbarReducerResult =
if (state is State.Content) {
- state.copy(subscription = message.subscription) to emptySet()
+ state.copy(
+ subscription = message.subscriptionWithLimitType.subscription,
+ subscriptionLimitType = message.subscriptionWithLimitType.subscriptionLimitType
+ ) to emptySet()
} else {
state to emptySet()
}
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/view/StepQuizToolbarViewStateMapper.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/view/StepQuizToolbarViewStateMapper.kt
index f58fb71fcc..355c613ef1 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/view/StepQuizToolbarViewStateMapper.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz_toolbar/view/StepQuizToolbarViewStateMapper.kt
@@ -3,7 +3,6 @@ package org.hyperskill.app.step_quiz_toolbar.view
import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarFeature.State
import org.hyperskill.app.step_quiz_toolbar.presentation.StepQuizToolbarFeature.ViewState
import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
-import org.hyperskill.app.subscriptions.domain.model.getSubscriptionLimitType
object StepQuizToolbarViewStateMapper {
@@ -15,12 +14,7 @@ object StepQuizToolbarViewStateMapper {
State.Error -> ViewState.Error
is State.Content -> {
val stepsLimitLeft = state.subscription.stepsLimitLeft
- val subscriptionLimitType =
- state.subscription.getSubscriptionLimitType(
- isMobileContentTrialEnabled = state.isMobileContentTrialEnabled,
- canMakePayments = state.canMakePayment
- )
- if (subscriptionLimitType == SubscriptionLimitType.PROBLEMS && stepsLimitLeft != null) {
+ if (state.subscriptionLimitType == SubscriptionLimitType.PROBLEMS && stepsLimitLeft != null) {
ViewState.Content.Visible(stepsLimitLabel = stepsLimitLeft.toString())
} else {
ViewState.Content.Hidden
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/injection/StudyPlanWidgetComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/injection/StudyPlanWidgetComponentImpl.kt
index ae6d6923e4..45be5661b5 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/injection/StudyPlanWidgetComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/injection/StudyPlanWidgetComponentImpl.kt
@@ -16,9 +16,8 @@ internal class StudyPlanWidgetComponentImpl(private val appGraph: AppGraph) : St
.stateRepositoriesComponent.nextLearningActivityStateRepository,
currentProfileStateRepository = appGraph.profileDataComponent.currentProfileStateRepository,
currentStudyPlanStateRepository = appGraph.stateRepositoriesComponent.currentStudyPlanStateRepository,
- currentSubscriptionStateRepository = appGraph.stateRepositoriesComponent.currentSubscriptionStateRepository,
+ subscriptionInteractor = appGraph.subscriptionDataComponent.subscriptionsInteractor,
progressesRepository = appGraph.buildProgressesDataComponent().progressesRepository,
- purchaseInteractor = appGraph.buildPurchaseComponent().purchaseInteractor,
sentryInteractor = appGraph.sentryComponent.sentryInteractor
)
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/MainStudyPlanWidgetActionDispatcher.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/MainStudyPlanWidgetActionDispatcher.kt
index 63e9813a8e..ca36f34844 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/MainStudyPlanWidgetActionDispatcher.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/MainStudyPlanWidgetActionDispatcher.kt
@@ -8,10 +8,8 @@ import kotlinx.coroutines.flow.onEach
import org.hyperskill.app.core.presentation.ActionDispatcherOptions
import org.hyperskill.app.learning_activities.domain.repository.LearningActivitiesRepository
import org.hyperskill.app.learning_activities.domain.repository.NextLearningActivityStateRepository
-import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
import org.hyperskill.app.progresses.domain.repository.ProgressesRepository
-import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.sentry.domain.model.transaction.HyperskillSentryTransactionBuilder
import org.hyperskill.app.sentry.domain.withTransaction
@@ -20,8 +18,7 @@ import org.hyperskill.app.study_plan.widget.presentation.StudyPlanWidgetFeature.
import org.hyperskill.app.study_plan.widget.presentation.StudyPlanWidgetFeature.InternalAction
import org.hyperskill.app.study_plan.widget.presentation.StudyPlanWidgetFeature.InternalMessage
import org.hyperskill.app.study_plan.widget.presentation.StudyPlanWidgetFeature.Message
-import org.hyperskill.app.subscriptions.domain.model.orContentTrial
-import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
+import org.hyperskill.app.subscriptions.domain.interactor.SubscriptionsInteractor
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher
internal class MainStudyPlanWidgetActionDispatcher(
@@ -30,9 +27,8 @@ internal class MainStudyPlanWidgetActionDispatcher(
private val nextLearningActivityStateRepository: NextLearningActivityStateRepository,
private val currentProfileStateRepository: CurrentProfileStateRepository,
private val currentStudyPlanStateRepository: CurrentStudyPlanStateRepository,
- private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
+ private val subscriptionInteractor: SubscriptionsInteractor,
private val progressesRepository: ProgressesRepository,
- private val purchaseInteractor: PurchaseInteractor,
private val sentryInteractor: SentryInteractor
) : CoroutineActionDispatcher(config.createConfig()) {
@@ -43,6 +39,12 @@ internal class MainStudyPlanWidgetActionDispatcher(
onNewMessage(InternalMessage.ProfileChanged(profile))
}
.launchIn(actionScope)
+ subscriptionInteractor
+ .subscribeOnSubscriptionLimitType()
+ .onEach {
+ onNewMessage(InternalMessage.SubscriptionLimitTypeChanged(it))
+ }
+ .launchIn(actionScope)
}
override suspend fun doSuspendableAction(action: Action) {
@@ -76,14 +78,6 @@ internal class MainStudyPlanWidgetActionDispatcher(
is InternalAction.CaptureSentryException -> {
sentryInteractor.captureException(action.throwable)
}
- is InternalAction.FetchPaymentAbility -> {
- purchaseInteractor
- .canMakePayments()
- .getOrDefault(false)
- .let {
- onNewMessage(InternalMessage.FetchPaymentAbilityResult(it))
- }
- }
else -> {
// no op
}
@@ -107,8 +101,8 @@ internal class MainStudyPlanWidgetActionDispatcher(
learningActivityStates = action.learningActivityStates
)
}
- val subscriptionDeferred = async {
- currentSubscriptionStateRepository.getState()
+ val subscriptionWithLimitTypeDeferred = async {
+ subscriptionInteractor.getSubscriptionWithLimitType()
}
val profile = currentProfileStateRepository.getState().getOrNull()
@@ -124,25 +118,20 @@ internal class MainStudyPlanWidgetActionDispatcher(
}
}
- val canMakePayments = purchaseInteractor.canMakePayments().getOrDefault(false)
-
val learningActivitiesResponse = learningActivitiesDeferred.await().getOrThrow()
- val subscription =
- subscriptionDeferred
+ val subscriptionWithLimitType =
+ subscriptionWithLimitTypeDeferred
.await()
.getOrThrow()
- .orContentTrial(
- isMobileContentTrialEnabled = profile?.features?.isMobileContentTrialEnabled == true,
- canMakePayments = canMakePayments
- )
+
val trackProgress = trackProgressDeferred.await().getOrThrow()
StudyPlanWidgetFeature.LearningActivitiesWithSectionsFetchResult.Success(
learningActivities = learningActivitiesResponse.learningActivities,
studyPlanSections = learningActivitiesResponse.studyPlanSections,
- subscription = subscription,
learnedTopicsCount = trackProgress?.learnedTopicsCount ?: 0,
- canMakePayments = canMakePayments
+ subscription = subscriptionWithLimitType.subscription,
+ subscriptionLimitType = subscriptionWithLimitType.subscriptionLimitType
)
}
}.let(onNewMessage)
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetFeature.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetFeature.kt
index 2b6f0f8d52..122480a548 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetFeature.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetFeature.kt
@@ -8,11 +8,11 @@ import org.hyperskill.app.learning_activities.presentation.model.LearningActivit
import org.hyperskill.app.paywall.domain.model.PaywallTransitionSource
import org.hyperskill.app.profile.domain.model.Profile
import org.hyperskill.app.profile.domain.model.isLearningPathDividedTrackTopicsEnabled
-import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
import org.hyperskill.app.sentry.domain.model.transaction.HyperskillSentryTransaction
import org.hyperskill.app.study_plan.domain.model.StudyPlanSection
import org.hyperskill.app.study_plan.domain.model.StudyPlanSectionType
import org.hyperskill.app.subscriptions.domain.model.Subscription
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
import org.hyperskill.app.topics.domain.model.TopicProgress
object StudyPlanWidgetFeature {
@@ -36,29 +36,21 @@ object StudyPlanWidgetFeature {
*/
val isRefreshing: Boolean = false,
- /**
- * Current user subscription
- */
- val subscription: Subscription? = null,
-
/**
* Actual learnedTopicsCount in the current track
*/
val learnedTopicsCount: Int = 0,
- val canMakePayments: Boolean = false
+ /**
+ * Subscription limit type
+ */
+ val subscriptionLimitType: SubscriptionLimitType = SubscriptionLimitType.NONE
) {
/**
* Divided track topics feature enabled flag
*/
val isLearningPathDividedTrackTopicsEnabled: Boolean
get() = profile?.features?.isLearningPathDividedTrackTopicsEnabled ?: false
-
- /**
- * MobileContentTrial feature flag
- */
- val isMobileContentTrialEnabled: Boolean
- get() = profile?.features?.isMobileContentTrialEnabled ?: false
}
enum class SectionStatus {
@@ -116,16 +108,22 @@ object StudyPlanWidgetFeature {
data class ProfileChanged(val profile: Profile) : InternalMessage
- data class FetchPaymentAbilityResult(val canMakePayments: Boolean) : InternalMessage
+ data class FetchSubscriptionLimitTypeResult(
+ val subscriptionLimitType: SubscriptionLimitType
+ ) : InternalMessage
+
+ data class SubscriptionLimitTypeChanged(
+ val subscriptionLimitType: SubscriptionLimitType
+ ) : InternalMessage
}
internal sealed interface LearningActivitiesWithSectionsFetchResult : Message {
data class Success(
val learningActivities: List,
val studyPlanSections: List,
- val subscription: Subscription,
val learnedTopicsCount: Int,
- val canMakePayments: Boolean
+ val subscription: Subscription,
+ val subscriptionLimitType: SubscriptionLimitType
) : LearningActivitiesWithSectionsFetchResult
data object Failed : LearningActivitiesWithSectionsFetchResult
@@ -178,8 +176,6 @@ object StudyPlanWidgetFeature {
data class PutTopicsProgressesToCache(val topicsProgresses: List) : InternalAction
- data object FetchPaymentAbility : InternalAction
-
data class CaptureSentryException(val throwable: Throwable) : InternalAction
data class LogAnalyticEvent(val analyticEvent: AnalyticEvent) : InternalAction
}
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetReducer.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetReducer.kt
index b7d62f5c7f..2ea1eac615 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetReducer.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetReducer.kt
@@ -112,8 +112,10 @@ class StudyPlanWidgetReducer : StateReducer {
)
)
)
- is InternalMessage.FetchPaymentAbilityResult ->
- handleFetchPaymentAbilityResult(state, message)
+ is InternalMessage.FetchSubscriptionLimitTypeResult ->
+ handleFetchSubscriptionLimitTypeResult(state, message)
+ is InternalMessage.SubscriptionLimitTypeChanged ->
+ handleSubscriptionLimitTypeChanged(state, message)
} ?: (state to emptySet())
private fun coldContentFetch(state: State, message: InternalMessage.Initialize): StudyPlanWidgetReducerResult =
@@ -130,8 +132,7 @@ class StudyPlanWidgetReducer : StateReducer {
setOfNotNull(
InternalAction.FetchLearningActivitiesWithSections(),
InternalAction.FetchProfile,
- InternalAction.UpdateCurrentStudyPlanState(forceUpdate),
- if (forceUpdate) InternalAction.FetchPaymentAbility else null
+ InternalAction.UpdateCurrentStudyPlanState(forceUpdate)
)
private fun handleLearningActivitiesWithSectionsFetchSuccess(
@@ -143,7 +144,8 @@ class StudyPlanWidgetReducer : StateReducer {
val currentSectionId = visibleSections.firstOrNull()?.id ?: return state.copy(
studyPlanSections = emptyMap(),
sectionsStatus = StudyPlanWidgetFeature.SectionStatus.LOADED,
- isRefreshing = false
+ isRefreshing = false,
+ subscriptionLimitType = message.subscriptionLimitType
) to emptySet()
val supportedSections = visibleSections
@@ -172,10 +174,9 @@ class StudyPlanWidgetReducer : StateReducer {
studyPlanSections = studyPlanSections,
sectionsStatus = StudyPlanWidgetFeature.SectionStatus.LOADED,
isRefreshing = false,
- subscription = message.subscription,
learnedTopicsCount = message.learnedTopicsCount,
- canMakePayments = message.canMakePayments,
- activities = message.learningActivities.associateBy { it.id }
+ activities = message.learningActivities.associateBy { it.id },
+ subscriptionLimitType = message.subscriptionLimitType
)
return if (loadedSectionsState.studyPlanSections.isNotEmpty()) {
@@ -477,11 +478,17 @@ class StudyPlanWidgetReducer : StateReducer {
state to emptySet()
}
- private fun handleFetchPaymentAbilityResult(
+ private fun handleFetchSubscriptionLimitTypeResult(
+ state: State,
+ message: InternalMessage.FetchSubscriptionLimitTypeResult
+ ): StudyPlanWidgetReducerResult =
+ state.copy(subscriptionLimitType = message.subscriptionLimitType) to emptySet()
+
+ private fun handleSubscriptionLimitTypeChanged(
state: State,
- message: InternalMessage.FetchPaymentAbilityResult
+ message: InternalMessage.SubscriptionLimitTypeChanged
): StudyPlanWidgetReducerResult =
- state.copy(canMakePayments = message.canMakePayments) to emptySet()
+ state.copy(subscriptionLimitType = message.subscriptionLimitType) to emptySet()
private fun getFetchLearningActivitiesSentryTransaction(
state: State,
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetStateExtensions.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetStateExtensions.kt
index daa5a202e5..d5e2904a35 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetStateExtensions.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/study_plan/widget/presentation/StudyPlanWidgetStateExtensions.kt
@@ -6,7 +6,6 @@ import org.hyperskill.app.study_plan.domain.model.StudyPlanSection
import org.hyperskill.app.study_plan.domain.model.StudyPlanSectionType
import org.hyperskill.app.study_plan.domain.model.rootTopicsActivitiesToBeLoaded
import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
-import org.hyperskill.app.subscriptions.domain.model.getSubscriptionLimitType
/**
* @return current [StudyPlanSection].
@@ -100,11 +99,7 @@ internal fun StudyPlanWidgetFeature.State.isActivityLocked(
internal fun StudyPlanWidgetFeature.State.getUnlockedActivitiesCount(sectionId: Long): Int? {
val section = studyPlanSections[sectionId]?.studyPlanSection ?: return null
val isRootTopicsSection = section.type == StudyPlanSectionType.ROOT_TOPICS
- val isTopicsLimitEnabled =
- subscription?.getSubscriptionLimitType(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- ) == SubscriptionLimitType.TOPICS
+ val isTopicsLimitEnabled = subscriptionLimitType == SubscriptionLimitType.TOPICS
val unlockedActivitiesCount = profile?.featureValues?.mobileContentTrialFreeTopics?.minus(learnedTopicsCount)
return if (isRootTopicsSection && isTopicsLimitEnabled && unlockedActivitiesCount != null) {
unlockedActivitiesCount
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/data/repository/CurrentSubscriptionStateRepositoryImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/data/repository/CurrentSubscriptionStateRepositoryImpl.kt
index 026de22c60..3e4bd04eff 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/data/repository/CurrentSubscriptionStateRepositoryImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/data/repository/CurrentSubscriptionStateRepositoryImpl.kt
@@ -1,15 +1,34 @@
package org.hyperskill.app.subscriptions.data.repository
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
import org.hyperskill.app.core.data.repository.BaseStateRepository
+import org.hyperskill.app.features.data.source.FeaturesDataSource
+import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
+import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.subscriptions.data.source.CurrentSubscriptionStateHolder
import org.hyperskill.app.subscriptions.data.source.SubscriptionsRemoteDataSource
import org.hyperskill.app.subscriptions.domain.model.Subscription
+import org.hyperskill.app.subscriptions.domain.model.orContentTrial
import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
internal class CurrentSubscriptionStateRepositoryImpl(
private val subscriptionsRemoteDataSource: SubscriptionsRemoteDataSource,
- override val stateHolder: CurrentSubscriptionStateHolder
+ override val stateHolder: CurrentSubscriptionStateHolder,
+ private val featuresDataSource: FeaturesDataSource,
+ private val purchaseInteractor: PurchaseInteractor,
) : CurrentSubscriptionStateRepository, BaseStateRepository() {
override suspend fun loadState(): Result =
- subscriptionsRemoteDataSource.getCurrentSubscription()
+ subscriptionsRemoteDataSource
+ .getCurrentSubscription()
+ .map { mapSubscription(it) }
+
+ override val changes: Flow
+ get() = super.changes.map(::mapSubscription)
+
+ private suspend fun mapSubscription(subscription: Subscription): Subscription =
+ subscription.orContentTrial(
+ isMobileContentTrialEnabled = featuresDataSource.getFeaturesMap().isMobileContentTrialEnabled,
+ canMakePayments = purchaseInteractor.canMakePayments().getOrDefault(false)
+ )
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/interactor/SubscriptionsInteractor.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/interactor/SubscriptionsInteractor.kt
index 0cebfbb86f..239427da88 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/interactor/SubscriptionsInteractor.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/interactor/SubscriptionsInteractor.kt
@@ -6,6 +6,8 @@ import kotlin.time.toDuration
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
@@ -13,7 +15,9 @@ import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import kotlinx.datetime.toLocalDateTime
import org.hyperskill.app.auth.domain.interactor.AuthInteractor
+import org.hyperskill.app.core.domain.repository.StateWithSource
import org.hyperskill.app.core.domain.repository.updateState
+import org.hyperskill.app.features.data.source.FeaturesDataSource
import org.hyperskill.app.profile.domain.model.isFreemiumIncreaseLimitsForFirstStepCompletionEnabled
import org.hyperskill.app.profile.domain.model.isMobileContentTrialEnabled
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
@@ -21,14 +25,17 @@ import org.hyperskill.app.profile.domain.repository.isFreemiumWrongSubmissionCha
import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.subscriptions.domain.model.FreemiumChargeLimitsStrategy
import org.hyperskill.app.subscriptions.domain.model.Subscription
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
import org.hyperskill.app.subscriptions.domain.model.SubscriptionType
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionWithLimitType
+import org.hyperskill.app.subscriptions.domain.model.getSubscriptionLimitType
import org.hyperskill.app.subscriptions.domain.model.isActive
import org.hyperskill.app.subscriptions.domain.repository.CurrentSubscriptionStateRepository
-import org.hyperskill.app.subscriptions.domain.repository.areProblemsLimited
class SubscriptionsInteractor(
private val currentSubscriptionStateRepository: CurrentSubscriptionStateRepository,
private val currentProfileStateRepository: CurrentProfileStateRepository,
+ private val featuresDataSource: FeaturesDataSource,
private val purchaseInteractor: PurchaseInteractor,
private val authInteractor: AuthInteractor,
logger: Logger
@@ -44,19 +51,71 @@ class SubscriptionsInteractor(
// Problems limits
- suspend fun getCurrentSubscription(): Result =
- currentSubscriptionStateRepository.getState(forceUpdate = false)
-
- suspend fun chargeProblemsLimits(chargeStrategy: FreemiumChargeLimitsStrategy) {
- val isMobileContentTrialEnabled = currentProfileStateRepository
- .getState()
- .map { it.features.isMobileContentTrialEnabled }
+ suspend fun isProblemsLimitEnabled(forceUpdate: Boolean = false): Boolean =
+ currentSubscriptionStateRepository
+ .getState(forceUpdate = forceUpdate)
+ .map {
+ val subscriptionLimitType = getSubscriptionLimitType(it)
+ subscriptionLimitType == SubscriptionLimitType.PROBLEMS
+ }
.getOrDefault(false)
- val areProblemsLimitEnabled = currentSubscriptionStateRepository.areProblemsLimited(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
+
+ suspend fun getSubscriptionLimitType(forceUpdate: Boolean = false): Result =
+ currentSubscriptionStateRepository
+ .getState(forceUpdate = forceUpdate)
+ .map {
+ getSubscriptionLimitType(it)
+ }
+
+ suspend fun getSubscriptionWithLimitType(forceUpdate: Boolean = false): Result =
+ currentSubscriptionStateRepository
+ .getState(forceUpdate = forceUpdate)
+ .map {
+ SubscriptionWithLimitType(
+ subscription = it,
+ subscriptionLimitType = getSubscriptionLimitType(it)
+ )
+ }
+
+ suspend fun getSubscriptionWithLimitTypeWithSource(
+ forceUpdate: Boolean = false
+ ): Result> =
+ currentSubscriptionStateRepository
+ .getStateWithSource(forceUpdate = forceUpdate)
+ .map {
+ StateWithSource(
+ state = SubscriptionWithLimitType(
+ subscription = it.state,
+ subscriptionLimitType = getSubscriptionLimitType(it.state)
+ ),
+ usedDataSourceType = it.usedDataSourceType
+ )
+ }
+
+ fun subscribeOnSubscriptionLimitType(): Flow =
+ currentSubscriptionStateRepository
+ .changes
+ .map(::getSubscriptionLimitType)
+
+ fun subscribeOnSubscriptionWithLimitType(): Flow =
+ currentSubscriptionStateRepository
+ .changes
+ .map {
+ SubscriptionWithLimitType(
+ subscription = it,
+ subscriptionLimitType = getSubscriptionLimitType(it)
+ )
+ }
+
+ private suspend fun getSubscriptionLimitType(subscription: Subscription): SubscriptionLimitType =
+ subscription.getSubscriptionLimitType(
+ isMobileContentTrialEnabled = featuresDataSource.getFeaturesMap().isMobileContentTrialEnabled,
canMakePayments = purchaseInteractor.canMakePayments().getOrDefault(false)
)
- if (areProblemsLimitEnabled) {
+
+ suspend fun chargeProblemsLimits(chargeStrategy: FreemiumChargeLimitsStrategy) {
+ val isProblemsLimitEnabled = isProblemsLimitEnabled()
+ if (isProblemsLimitEnabled) {
when (chargeStrategy) {
FreemiumChargeLimitsStrategy.AFTER_WRONG_SUBMISSION -> chargeLimitsAfterWrongSubmission()
FreemiumChargeLimitsStrategy.AFTER_CORRECT_SUBMISSION -> chargeLimitsAfterCorrectSubmission()
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/model/Subscription.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/model/Subscription.kt
index 0de77e2126..86c91605cf 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/model/Subscription.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/model/Subscription.kt
@@ -54,22 +54,11 @@ internal fun Subscription.getSubscriptionLimitType(
else -> type.subscriptionLimitType
}
-internal fun Subscription.isProblemsLimitReached(
- isMobileContentTrialEnabled: Boolean,
- canMakePayments: Boolean
-): Boolean {
- val subscriptionLimitType = getSubscriptionLimitType(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- return subscriptionLimitType == SubscriptionLimitType.PROBLEMS && stepsLimitLeft == 0
-}
-
internal val Subscription.isFreemium: Boolean
get() = type == SubscriptionType.FREEMIUM ||
type == SubscriptionType.MOBILE_ONLY && status != SubscriptionStatus.ACTIVE
-fun Subscription.orContentTrial(
+internal fun Subscription.orContentTrial(
isMobileContentTrialEnabled: Boolean,
canMakePayments: Boolean
): Subscription =
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/model/SubscriptionWithLimitType.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/model/SubscriptionWithLimitType.kt
new file mode 100644
index 0000000000..dffbe15434
--- /dev/null
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/model/SubscriptionWithLimitType.kt
@@ -0,0 +1,9 @@
+package org.hyperskill.app.subscriptions.domain.model
+
+data class SubscriptionWithLimitType(
+ val subscription: Subscription,
+ val subscriptionLimitType: SubscriptionLimitType
+)
+
+val SubscriptionWithLimitType.isProblemsLimitReached: Boolean
+ get() = subscriptionLimitType == SubscriptionLimitType.PROBLEMS && subscription.stepsLimitLeft == 0
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/repository/CurrentSubscriptionStateRepository.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/repository/CurrentSubscriptionStateRepository.kt
index 18b63597aa..2a95409c46 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/repository/CurrentSubscriptionStateRepository.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/domain/repository/CurrentSubscriptionStateRepository.kt
@@ -2,22 +2,5 @@ package org.hyperskill.app.subscriptions.domain.repository
import org.hyperskill.app.core.domain.repository.StateRepository
import org.hyperskill.app.subscriptions.domain.model.Subscription
-import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
-import org.hyperskill.app.subscriptions.domain.model.getSubscriptionLimitType
-interface CurrentSubscriptionStateRepository : StateRepository
-
-internal suspend fun CurrentSubscriptionStateRepository.areProblemsLimited(
- isMobileContentTrialEnabled: Boolean,
- canMakePayments: Boolean
-): Boolean =
- getState(forceUpdate = false)
- .map {
- val subscriptionLimitType =
- it.getSubscriptionLimitType(
- isMobileContentTrialEnabled = isMobileContentTrialEnabled,
- canMakePayments = canMakePayments
- )
- subscriptionLimitType == SubscriptionLimitType.PROBLEMS
- }
- .getOrDefault(defaultValue = false)
\ No newline at end of file
+interface CurrentSubscriptionStateRepository : StateRepository
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/injection/SubscriptionsDataComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/injection/SubscriptionsDataComponentImpl.kt
index 74dc9050b3..5f2b0a4de0 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/injection/SubscriptionsDataComponentImpl.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/subscriptions/injection/SubscriptionsDataComponentImpl.kt
@@ -3,6 +3,7 @@ package org.hyperskill.app.subscriptions.injection
import co.touchlab.kermit.Logger
import org.hyperskill.app.auth.domain.interactor.AuthInteractor
import org.hyperskill.app.core.injection.AppGraph
+import org.hyperskill.app.features.data.source.FeaturesDataSource
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
import org.hyperskill.app.purchases.domain.interactor.PurchaseInteractor
import org.hyperskill.app.subscriptions.data.repository.SubscriptionsRepositoryImpl
@@ -24,6 +25,9 @@ class SubscriptionsDataComponentImpl(
private val currentProfileStateRepository: CurrentProfileStateRepository =
appGraph.profileDataComponent.currentProfileStateRepository
+ private val featuresDataSource: FeaturesDataSource =
+ appGraph.profileDataComponent.featuresDataSource
+
private val purchaseInteractor: PurchaseInteractor =
appGraph.buildPurchaseComponent().purchaseInteractor
@@ -42,6 +46,7 @@ class SubscriptionsDataComponentImpl(
currentProfileStateRepository = currentProfileStateRepository,
purchaseInteractor = purchaseInteractor,
authInteractor = authInteractor,
+ featuresDataSource = featuresDataSource,
logger = logger
)
}
diff --git a/shared/src/commonTest/kotlin/org/hyperskill/study_plan/widget/StudyPlanWidgetStateExtensionsTest.kt b/shared/src/commonTest/kotlin/org/hyperskill/study_plan/widget/StudyPlanWidgetStateExtensionsTest.kt
index bd83db57db..8d4e0108c0 100644
--- a/shared/src/commonTest/kotlin/org/hyperskill/study_plan/widget/StudyPlanWidgetStateExtensionsTest.kt
+++ b/shared/src/commonTest/kotlin/org/hyperskill/study_plan/widget/StudyPlanWidgetStateExtensionsTest.kt
@@ -20,9 +20,7 @@ import org.hyperskill.app.study_plan.widget.presentation.getLoadedSectionActivit
import org.hyperskill.app.study_plan.widget.presentation.getUnlockedActivitiesCount
import org.hyperskill.app.study_plan.widget.presentation.isActivityLocked
import org.hyperskill.app.study_plan.widget.presentation.isPaywallShown
-import org.hyperskill.app.subscriptions.domain.model.Subscription
-import org.hyperskill.app.subscriptions.domain.model.SubscriptionStatus
-import org.hyperskill.app.subscriptions.domain.model.SubscriptionType
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
import org.hyperskill.learning_activities.domain.model.stub
import org.hyperskill.profile.stub
import org.hyperskill.study_plan.domain.model.stub
@@ -155,7 +153,7 @@ class StudyPlanWidgetStateExtensionsTest {
}
@Test
- fun `isActivityLocked should return true if activity is locked`() {
+ fun `isActivityLocked should return true for locked activities in case of topics limit`() {
val section = StudyPlanSection.stub(
id = 1,
type = StudyPlanSectionType.ROOT_TOPICS,
@@ -171,10 +169,7 @@ class StudyPlanWidgetStateExtensionsTest {
),
activities = mapOf(1L to LearningActivity.stub(id = 1)),
profile = Profile.stub(),
- subscription = Subscription(
- type = SubscriptionType.MOBILE_CONTENT_TRIAL,
- status = SubscriptionStatus.ACTIVE
- ),
+ subscriptionLimitType = SubscriptionLimitType.TOPICS,
learnedTopicsCount = 1
)
@@ -201,10 +196,7 @@ class StudyPlanWidgetStateExtensionsTest {
featureValues = FeatureValues(mobileContentTrialFreeTopics = 2),
featuresMap = mapOf(FeatureKeys.MOBILE_CONTENT_TRIAL to true),
),
- subscription = Subscription(
- type = SubscriptionType.MOBILE_CONTENT_TRIAL,
- status = SubscriptionStatus.ACTIVE
- ),
+ subscriptionLimitType = SubscriptionLimitType.TOPICS,
learnedTopicsCount = 1
)
@@ -231,10 +223,7 @@ class StudyPlanWidgetStateExtensionsTest {
featureValues = FeatureValues(mobileContentTrialFreeTopics = 2),
featuresMap = mapOf(FeatureKeys.MOBILE_CONTENT_TRIAL to true),
),
- subscription = Subscription(
- type = SubscriptionType.MOBILE_CONTENT_TRIAL,
- status = SubscriptionStatus.ACTIVE
- ),
+ subscriptionLimitType = SubscriptionLimitType.TOPICS,
learnedTopicsCount = 1
)
@@ -261,10 +250,7 @@ class StudyPlanWidgetStateExtensionsTest {
featureValues = FeatureValues(mobileContentTrialFreeTopics = 10),
featuresMap = mapOf(FeatureKeys.MOBILE_CONTENT_TRIAL to true),
),
- subscription = Subscription(
- type = SubscriptionType.MOBILE_CONTENT_TRIAL,
- status = SubscriptionStatus.ACTIVE
- ),
+ subscriptionLimitType = SubscriptionLimitType.TOPICS,
learnedTopicsCount = 10
)
@@ -291,10 +277,7 @@ class StudyPlanWidgetStateExtensionsTest {
featureValues = FeatureValues(mobileContentTrialFreeTopics = 10),
featuresMap = mapOf(FeatureKeys.MOBILE_CONTENT_TRIAL to true),
),
- subscription = Subscription(
- type = SubscriptionType.MOBILE_CONTENT_TRIAL,
- status = SubscriptionStatus.ACTIVE
- ),
+ subscriptionLimitType = SubscriptionLimitType.TOPICS,
learnedTopicsCount = 10
)
@@ -332,10 +315,7 @@ class StudyPlanWidgetStateExtensionsTest {
featureValues = FeatureValues(mobileContentTrialFreeTopics = 10),
featuresMap = mapOf(FeatureKeys.MOBILE_CONTENT_TRIAL to true),
),
- subscription = Subscription(
- type = SubscriptionType.MOBILE_CONTENT_TRIAL,
- status = SubscriptionStatus.ACTIVE
- ),
+ subscriptionLimitType = SubscriptionLimitType.TOPICS,
learnedTopicsCount = 10
)
@@ -362,10 +342,7 @@ class StudyPlanWidgetStateExtensionsTest {
featureValues = FeatureValues(mobileContentTrialFreeTopics = 10),
featuresMap = mapOf(FeatureKeys.MOBILE_CONTENT_TRIAL to true),
),
- subscription = Subscription(
- type = SubscriptionType.MOBILE_CONTENT_TRIAL,
- status = SubscriptionStatus.ACTIVE
- ),
+ subscriptionLimitType = SubscriptionLimitType.TOPICS,
learnedTopicsCount = 5
)
diff --git a/shared/src/commonTest/kotlin/org/hyperskill/study_plan/widget/StudyPlanWidgetTest.kt b/shared/src/commonTest/kotlin/org/hyperskill/study_plan/widget/StudyPlanWidgetTest.kt
index ba5e78c649..4c024675d6 100644
--- a/shared/src/commonTest/kotlin/org/hyperskill/study_plan/widget/StudyPlanWidgetTest.kt
+++ b/shared/src/commonTest/kotlin/org/hyperskill/study_plan/widget/StudyPlanWidgetTest.kt
@@ -29,6 +29,7 @@ import org.hyperskill.app.study_plan.widget.presentation.StudyPlanWidgetReducer
import org.hyperskill.app.study_plan.widget.view.mapper.StudyPlanWidgetViewStateMapper
import org.hyperskill.app.study_plan.widget.view.model.StudyPlanWidgetViewState
import org.hyperskill.app.subscriptions.domain.model.Subscription
+import org.hyperskill.app.subscriptions.domain.model.SubscriptionLimitType
import org.hyperskill.app.subscriptions.domain.model.SubscriptionStatus
import org.hyperskill.app.subscriptions.domain.model.SubscriptionType
import org.hyperskill.learning_activities.domain.model.stub
@@ -62,7 +63,7 @@ class StudyPlanWidgetTest {
learningActivities = emptyList(),
studyPlanSections = emptyList(),
subscription = Subscription.stub(),
- canMakePayments = false,
+ subscriptionLimitType = SubscriptionLimitType.NONE,
learnedTopicsCount = 0
)
)
@@ -90,7 +91,7 @@ class StudyPlanWidgetTest {
visibleSection
),
subscription = Subscription.stub(),
- canMakePayments = false,
+ subscriptionLimitType = SubscriptionLimitType.NONE,
learnedTopicsCount = 0
)
)
@@ -121,7 +122,7 @@ class StudyPlanWidgetTest {
learningActivities = listOf(stubLearningActivity(id = 1L)),
studyPlanSections = listOf(visibleSection, currentSection),
subscription = Subscription.stub(),
- canMakePayments = false,
+ subscriptionLimitType = SubscriptionLimitType.NONE,
learnedTopicsCount = 0
)
)
@@ -159,7 +160,7 @@ class StudyPlanWidgetTest {
)
),
subscription = subscription,
- canMakePayments = false,
+ subscriptionLimitType = SubscriptionLimitType.NONE,
learnedTopicsCount = 0
)
)
@@ -186,7 +187,7 @@ class StudyPlanWidgetTest {
studyPlanSectionStub(id = 1, activities = listOf(1))
),
subscription = Subscription.stub(),
- canMakePayments = false,
+ subscriptionLimitType = SubscriptionLimitType.NONE,
learnedTopicsCount = 0
)
)
@@ -239,7 +240,7 @@ class StudyPlanWidgetTest {
)
},
subscription = Subscription.stub(),
- canMakePayments = false,
+ subscriptionLimitType = SubscriptionLimitType.NONE,
learnedTopicsCount = 0
)
)
@@ -264,7 +265,7 @@ class StudyPlanWidgetTest {
),
studyPlanSections = listOf(firstSection, secondSection),
subscription = Subscription.stub(),
- canMakePayments = false,
+ subscriptionLimitType = SubscriptionLimitType.NONE,
learnedTopicsCount = 0
)
)