1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-2275 Membership | Status provider (#1119)

This commit is contained in:
Konstantin Ivanov 2024-04-16 11:53:13 +02:00 committed by GitHub
parent 2ccbdc37d4
commit 6ece50176c
Signed by: github
GPG key ID: B5690EEEBB952194
25 changed files with 372 additions and 66 deletions

View file

@ -25,6 +25,7 @@ import com.anytypeio.anytype.domain.wallpaper.RestoreWallpaper
import com.anytypeio.anytype.domain.wallpaper.WallpaperStore
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.main.MainViewModelFactory
import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider
import com.anytypeio.anytype.presentation.notifications.NotificationsProvider
import com.anytypeio.anytype.ui.main.MainActivity
import com.anytypeio.anytype.ui_settings.appearance.ThemeApplicator
@ -67,7 +68,8 @@ object MainEntryModule {
spaceDeletedStatusWatcher: SpaceDeletedStatusWatcher,
localeProvider: LocaleProvider,
userPermissionProvider: UserPermissionProvider,
notificationsProvider: NotificationsProvider
notificationsProvider: NotificationsProvider,
membershipProvider: MembershipProvider
): MainViewModelFactory = MainViewModelFactory(
resumeAccount = resumeAccount,
analytics = analytics,
@ -82,7 +84,8 @@ object MainEntryModule {
spaceDeletedStatusWatcher = spaceDeletedStatusWatcher,
localeProvider = localeProvider,
userPermissionProvider = userPermissionProvider,
notificationsProvider = notificationsProvider
notificationsProvider = notificationsProvider,
membershipProvider = membershipProvider
)
@JvmStatic

View file

@ -8,6 +8,8 @@ import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.auth.interactor.GetAccount
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.payments.GetMembershipTiers
import com.anytypeio.anytype.payments.playbilling.BillingClientLifecycle
import com.anytypeio.anytype.ui.payments.PaymentsFragment
import com.anytypeio.anytype.payments.viewmodel.PaymentsViewModelFactory
@ -45,6 +47,14 @@ object PaymentsModule {
dispatchers: AppCoroutineDispatchers
): GetAccount = GetAccount(repo = repo, dispatcher = dispatchers)
@JvmStatic
@Provides
@PerScreen
fun provideGetTiersUseCase(
repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
): GetMembershipTiers = GetMembershipTiers(repo = repo, dispatchers = dispatchers)
@Module
interface Declarations {
@ -62,5 +72,6 @@ interface PaymentsComponentDependencies : ComponentDependencies {
fun context(): Context
fun billingListener(): BillingClientLifecycle
fun authRepository(): AuthRepository
fun blockRepository(): BlockRepository
fun appCoroutineDispatchers(): AppCoroutineDispatchers
}

View file

@ -1,28 +0,0 @@
package com.anytypeio.anytype.di.main
import android.content.Context
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.payments.playbilling.BillingClientLifecycle
import dagger.Module
import dagger.Provides
import javax.inject.Named
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope
@Module
object BillingModule {
@Singleton
@Provides
fun provideBillingLifecycle(
context: Context,
dispatchers: AppCoroutineDispatchers,
@Named(ConfigModule.DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope
): BillingClientLifecycle {
return BillingClientLifecycle(
dispatchers = dispatchers,
applicationContext = context,
scope = scope
)
}
}

View file

@ -11,7 +11,6 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.device.FileSharer
import com.anytypeio.anytype.domain.download.Downloader
import com.anytypeio.anytype.domain.misc.LocaleProvider
import com.anytypeio.anytype.providers.DefaultUriFileProvider
import dagger.Module
import dagger.Provides
import javax.inject.Singleton

View file

@ -80,7 +80,7 @@ import javax.inject.Singleton
TemplatesModule::class,
NetworkModeModule::class,
NotificationsModule::class,
BillingModule::class
MembershipModule::class
]
)
interface MainComponent :

View file

@ -0,0 +1,72 @@
package com.anytypeio.anytype.di.main
import android.content.Context
import com.anytypeio.anytype.data.auth.event.MembershipDateChannel
import com.anytypeio.anytype.data.auth.event.MembershipRemoteChannel
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.misc.LocaleProvider
import com.anytypeio.anytype.domain.workspace.MembershipChannel
import com.anytypeio.anytype.middleware.EventProxy
import com.anytypeio.anytype.middleware.interactor.MembershipMiddlewareChannel
import com.anytypeio.anytype.payments.playbilling.BillingClientLifecycle
import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider
import dagger.Module
import dagger.Provides
import javax.inject.Named
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope
@Module
object MembershipModule {
@Singleton
@Provides
fun provideBillingLifecycle(
context: Context,
dispatchers: AppCoroutineDispatchers,
@Named(ConfigModule.DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope
): BillingClientLifecycle {
return BillingClientLifecycle(
dispatchers = dispatchers,
applicationContext = context,
scope = scope
)
}
@JvmStatic
@Provides
@Singleton
fun provideMembershipRemoteChannel(
proxy: EventProxy
): MembershipRemoteChannel = MembershipMiddlewareChannel(
eventsProxy = proxy
)
@JvmStatic
@Provides
@Singleton
fun provideMembershipChannel(
channel: MembershipRemoteChannel
): MembershipChannel = MembershipDateChannel(
channel = channel
)
@JvmStatic
@Singleton
@Provides
fun provideMembershipProvider(
dispatchers: AppCoroutineDispatchers,
awaitAccountStartManager: AwaitAccountStartManager,
membershipChannel: MembershipChannel,
localeProvider: LocaleProvider,
repo: BlockRepository
): MembershipProvider = MembershipProvider.Default(
dispatchers = dispatchers,
membershipChannel = membershipChannel,
awaitAccountStartManager = awaitAccountStartManager,
localeProvider = localeProvider,
repo = repo
)
}

View file

@ -2,7 +2,7 @@ package com.anytypeio.anytype.core_models.membership
data class Membership(
val tier: Int,
val membershipStatus: MembershipStatus,
val membershipStatusModel: MembershipStatusModel,
val dateStarted: Long,
val dateEnds: Long,
val isAutoRenew: Boolean,
@ -10,9 +10,12 @@ data class Membership(
val requestedAnyName: String,
val userEmail: String,
val subscribeToNewsletter: Boolean
)
) {
enum class MembershipStatus {
data class Event(val membership: Membership)
}
enum class MembershipStatusModel {
STATUS_UNKNOWN,
STATUS_PENDING,
STATUS_ACTIVE,

View file

@ -0,0 +1,18 @@
package com.anytypeio.anytype.data.auth.event
import com.anytypeio.anytype.core_models.membership.Membership
import com.anytypeio.anytype.domain.workspace.MembershipChannel
import kotlinx.coroutines.flow.Flow
interface MembershipRemoteChannel {
fun observe(): Flow<List<Membership.Event>>
}
class MembershipDateChannel(
private val channel: MembershipRemoteChannel
) : MembershipChannel {
override fun observe(): Flow<List<Membership.Event>> {
return channel.observe()
}
}

View file

@ -0,0 +1,25 @@
package com.anytypeio.anytype.domain.payments
import com.anytypeio.anytype.core_models.Command
import com.anytypeio.anytype.core_models.membership.Membership
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import javax.inject.Inject
class GetMembershipStatus @Inject constructor(
dispatchers: AppCoroutineDispatchers,
private val repo: BlockRepository
) : ResultInteractor<GetMembershipStatus.Params, Membership?>(dispatchers.io) {
override suspend fun doWork(params: Params): Membership? {
val command = Command.Membership.GetStatus(
noCache = params.noCache
)
return repo.membershipStatus(command)
}
data class Params(
val noCache: Boolean
)
}

View file

@ -7,10 +7,10 @@ import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import javax.inject.Inject
class GetTiers @Inject constructor(
class GetMembershipTiers @Inject constructor(
dispatchers: AppCoroutineDispatchers,
private val repo: BlockRepository
) : ResultInteractor<GetTiers.Params, List<MembershipTierData>>(dispatchers.io) {
) : ResultInteractor<GetMembershipTiers.Params, List<MembershipTierData>>(dispatchers.io) {
override suspend fun doWork(params: Params): List<MembershipTierData> {
val command = Command.Membership.GetTiers(

View file

@ -0,0 +1,8 @@
package com.anytypeio.anytype.domain.workspace
import com.anytypeio.anytype.core_models.membership.Membership
import kotlinx.coroutines.flow.Flow
interface MembershipChannel {
fun observe(): Flow<List<Membership.Event>>
}

View file

@ -0,0 +1,37 @@
package com.anytypeio.anytype.middleware.interactor
import com.anytypeio.anytype.core_models.membership.Membership
import com.anytypeio.anytype.data.auth.event.MembershipRemoteChannel
import com.anytypeio.anytype.middleware.EventProxy
import com.anytypeio.anytype.middleware.mappers.toCoreModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.mapNotNull
class MembershipMiddlewareChannel(
private val eventsProxy: EventProxy
): MembershipRemoteChannel {
override fun observe(): Flow<List<Membership.Event>> {
return eventsProxy.flow()
.mapNotNull { emission ->
emission.messages.mapNotNull { message ->
when {
message.membershipUpdate != null -> {
val event = message.membershipUpdate
checkNotNull(event)
val membership = event.data_
if (membership != null) {
Membership.Event(
membership = membership.toCoreModel()
)
} else {
null
}
}
else -> null
}
}
}.filter { events -> events.isNotEmpty() }
}
}

View file

@ -46,7 +46,7 @@ import com.anytypeio.anytype.core_models.membership.EmailVerificationStatus
import com.anytypeio.anytype.core_models.membership.Membership
import com.anytypeio.anytype.core_models.membership.MembershipPaymentMethod
import com.anytypeio.anytype.core_models.membership.MembershipPeriodType
import com.anytypeio.anytype.core_models.membership.MembershipStatus
import com.anytypeio.anytype.core_models.membership.MembershipStatusModel
import com.anytypeio.anytype.core_models.membership.MembershipTierData
import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions
import com.anytypeio.anytype.core_models.primitives.SpaceId
@ -975,12 +975,12 @@ fun MNotification.toCoreModel(): Notification {
//endregion
//region MEMBERSHIP
fun MMembershipStatus.toCoreModel(): MembershipStatus {
fun MMembershipStatus.toCoreModel(): MembershipStatusModel {
return when (this) {
MMembershipStatus.StatusUnknown -> MembershipStatus.STATUS_UNKNOWN
MMembershipStatus.StatusPending -> MembershipStatus.STATUS_PENDING
MMembershipStatus.StatusActive -> MembershipStatus.STATUS_ACTIVE
MMembershipStatus.StatusPendingRequiresFinalization -> MembershipStatus.STATUS_PENDING_FINALIZATION
MMembershipStatus.StatusUnknown -> MembershipStatusModel.STATUS_UNKNOWN
MMembershipStatus.StatusPending -> MembershipStatusModel.STATUS_PENDING
MMembershipStatus.StatusActive -> MembershipStatusModel.STATUS_ACTIVE
MMembershipStatus.StatusPendingRequiresFinalization -> MembershipStatusModel.STATUS_PENDING_FINALIZATION
}
}
@ -997,7 +997,7 @@ fun MMembershipPaymentMethod.toCoreModel(): MembershipPaymentMethod {
fun MMembership.toCoreModel(): Membership {
return Membership(
tier = tier,
membershipStatus = status.toCoreModel(),
membershipStatusModel = status.toCoreModel(),
dateStarted = dateStarted,
dateEnds = dateEnds,
isAutoRenew = isAutoRenew,

View file

@ -52,7 +52,7 @@ import com.anytypeio.anytype.core_ui.views.HeadlineTitle
import com.anytypeio.anytype.core_ui.views.PreviewTitle1Regular
import com.anytypeio.anytype.payments.R
import com.anytypeio.anytype.payments.viewmodel.PaymentsCodeState
import com.anytypeio.anytype.payments.viewmodel.TierId
import com.anytypeio.anytype.presentation.membership.models.TierId
@OptIn(ExperimentalMaterial3Api::class)
@Composable

View file

@ -53,9 +53,9 @@ import com.anytypeio.anytype.core_ui.views.BodyRegular
import com.anytypeio.anytype.core_ui.views.Caption1Regular
import com.anytypeio.anytype.core_ui.views.Relations2
import com.anytypeio.anytype.core_ui.views.fontRiccioneRegular
import com.anytypeio.anytype.payments.models.Tier
import com.anytypeio.anytype.presentation.membership.models.Tier
import com.anytypeio.anytype.payments.viewmodel.PaymentsMainState
import com.anytypeio.anytype.payments.viewmodel.TierId
import com.anytypeio.anytype.presentation.membership.models.TierId
@Composable
fun MainPaymentsScreen(state: PaymentsMainState, tierClicked: (TierId) -> Unit) {

View file

@ -58,9 +58,9 @@ import com.anytypeio.anytype.core_ui.views.HeadlineTitle
import com.anytypeio.anytype.core_ui.views.Relations1
import com.anytypeio.anytype.core_ui.views.Relations2
import com.anytypeio.anytype.payments.R
import com.anytypeio.anytype.payments.models.Tier
import com.anytypeio.anytype.presentation.membership.models.Tier
import com.anytypeio.anytype.payments.viewmodel.PaymentsTierState
import com.anytypeio.anytype.payments.viewmodel.TierId
import com.anytypeio.anytype.presentation.membership.models.TierId
@OptIn(ExperimentalMaterial3Api::class)

View file

@ -27,9 +27,9 @@ import com.anytypeio.anytype.core_ui.views.ButtonSecondary
import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
import com.anytypeio.anytype.payments.R
import com.anytypeio.anytype.payments.models.Tier
import com.anytypeio.anytype.presentation.membership.models.Tier
import com.anytypeio.anytype.payments.viewmodel.PaymentsWelcomeState
import com.anytypeio.anytype.payments.viewmodel.TierId
import com.anytypeio.anytype.presentation.membership.models.TierId
@OptIn(ExperimentalMaterial3Api::class)
@Composable

View file

@ -37,7 +37,7 @@ import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.Caption1Regular
import com.anytypeio.anytype.core_ui.views.Relations3
import com.anytypeio.anytype.core_ui.views.fontInterSemibold
import com.anytypeio.anytype.payments.models.Tier
import com.anytypeio.anytype.presentation.membership.models.Tier
@Composable
fun TierView(

View file

@ -1,6 +1,7 @@
package com.anytypeio.anytype.payments.viewmodel
import com.anytypeio.anytype.payments.models.Tier
import com.anytypeio.anytype.presentation.membership.models.Tier
import com.anytypeio.anytype.presentation.membership.models.TierId
sealed class PaymentsMainState {
@ -44,7 +45,4 @@ sealed class PaymentsNavigation(val route: String) {
object Code : PaymentsNavigation("code")
object Welcome : PaymentsNavigation("welcome")
object Dismiss : PaymentsNavigation("")
}
@JvmInline
value class TierId(val value: String)
}

View file

@ -7,9 +7,12 @@ import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.Purchase
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.domain.auth.interactor.GetAccount
import com.anytypeio.anytype.domain.base.fold
import com.anytypeio.anytype.domain.payments.GetMembershipTiers
import com.anytypeio.anytype.payments.constants.BillingConstants
import com.anytypeio.anytype.payments.models.Tier
import com.anytypeio.anytype.presentation.membership.models.Tier
import com.anytypeio.anytype.payments.playbilling.BillingClientLifecycle
import com.anytypeio.anytype.presentation.membership.models.TierId
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
@ -19,7 +22,8 @@ import timber.log.Timber
class PaymentsViewModel(
private val analytics: Analytics,
private val billingClientLifecycle: BillingClientLifecycle,
private val getAccount: GetAccount
private val getAccount: GetAccount,
private val getMembershipTiers: GetMembershipTiers
) : ViewModel() {
val viewState = MutableStateFlow<PaymentsMainState>(PaymentsMainState.Loading)
@ -50,9 +54,19 @@ class PaymentsViewModel(
init {
Timber.d("PaymentsViewModel init")
_tiers.addAll(gertTiers())
proceedWithGetTiers()
setupActiveTierName()
viewState.value = PaymentsMainState.Default(_tiers)
}
private fun proceedWithGetTiers() {
viewModelScope.launch {
getMembershipTiers.async(GetMembershipTiers.Params("en", false)).fold(
onSuccess = { result ->
///todo handle the result
},
onFailure = Timber::e
)
}
}
fun onTierClicked(tierId: TierId) {

View file

@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.domain.auth.interactor.GetAccount
import com.anytypeio.anytype.domain.payments.GetMembershipTiers
import com.anytypeio.anytype.payments.playbilling.BillingClientLifecycle
import javax.inject.Inject
@ -11,13 +12,15 @@ class PaymentsViewModelFactory @Inject constructor(
private val analytics: Analytics,
private val billingClientLifecycle: BillingClientLifecycle,
private val getAccount: GetAccount,
private val getMembershipTiers: GetMembershipTiers
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return PaymentsViewModel(
analytics = analytics,
billingClientLifecycle = billingClientLifecycle,
getAccount = getAccount
getAccount = getAccount,
getMembershipTiers = getMembershipTiers
) as T
}
}

View file

@ -15,6 +15,7 @@ import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
import com.anytypeio.anytype.domain.wallpaper.RestoreWallpaper
import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider
import com.anytypeio.anytype.presentation.notifications.NotificationsProvider
import javax.inject.Inject
@ -32,7 +33,8 @@ class MainViewModelFactory @Inject constructor(
private val spaceDeletedStatusWatcher: SpaceDeletedStatusWatcher,
private val localeProvider: LocaleProvider,
private val userPermissionProvider: UserPermissionProvider,
private val notificationsProvider: NotificationsProvider
private val notificationsProvider: NotificationsProvider,
private val membershipProvider: MembershipProvider
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
@ -51,6 +53,7 @@ class MainViewModelFactory @Inject constructor(
spaceDeletedStatusWatcher = spaceDeletedStatusWatcher,
localeProvider = localeProvider,
userPermissionProvider = userPermissionProvider,
notificationsProvider = notificationsProvider
notificationsProvider = notificationsProvider,
membershipProvider = membershipProvider
) as T
}

View file

@ -0,0 +1,21 @@
package com.anytypeio.anytype.presentation.membership.models
import com.anytypeio.anytype.core_models.membership.MembershipPaymentMethod
import com.anytypeio.anytype.core_models.membership.MembershipStatusModel
import com.anytypeio.anytype.core_models.membership.MembershipTierData
sealed class MembershipStatus {
object Unknown : MembershipStatus()
object Pending : MembershipStatus()
object Finalization : MembershipStatus()
data class Active(
val tier: MembershipTierData?,
val status: MembershipStatusModel,
val dateEnds: Long,
val paymentMethod: MembershipPaymentMethod,
val anyName: String
) : MembershipStatus()
}
@JvmInline
value class TierId(val value: String)

View file

@ -1,6 +1,5 @@
package com.anytypeio.anytype.payments.models
package com.anytypeio.anytype.presentation.membership.models
import com.anytypeio.anytype.payments.viewmodel.TierId
sealed class Tier {
abstract val id: TierId

View file

@ -0,0 +1,120 @@
package com.anytypeio.anytype.presentation.membership.provider
import com.anytypeio.anytype.core_models.Command
import com.anytypeio.anytype.core_models.membership.Membership
import com.anytypeio.anytype.core_models.membership.MembershipStatusModel.STATUS_ACTIVE
import com.anytypeio.anytype.core_models.membership.MembershipStatusModel.STATUS_PENDING
import com.anytypeio.anytype.core_models.membership.MembershipStatusModel.STATUS_PENDING_FINALIZATION
import com.anytypeio.anytype.core_models.membership.MembershipStatusModel.STATUS_UNKNOWN
import com.anytypeio.anytype.core_models.membership.MembershipTierData
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.misc.LocaleProvider
import com.anytypeio.anytype.domain.workspace.MembershipChannel
import com.anytypeio.anytype.presentation.membership.models.MembershipStatus
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.scan
import timber.log.Timber
interface MembershipProvider {
fun status(): Flow<MembershipStatus>
class Default(
private val dispatchers: AppCoroutineDispatchers,
private val membershipChannel: MembershipChannel,
private val awaitAccountStartManager: AwaitAccountStartManager,
private val localeProvider: LocaleProvider,
private val repo: BlockRepository
) : MembershipProvider {
@OptIn(ExperimentalCoroutinesApi::class)
override fun status(): Flow<MembershipStatus> {
return awaitAccountStartManager.isStarted().flatMapLatest { isStarted ->
if (isStarted) {
buildStatusFlow(
initial = proceedWithGettingMembership()
)
} else {
emptyFlow()
}
}.catch { e -> Timber.e(e) }
.flowOn(dispatchers.io)
}
private fun buildStatusFlow(
initial: Membership?
): Flow<MembershipStatus> {
return membershipChannel
.observe()
.scan(initial) { _, events ->
events.lastOrNull()?.membership
}.mapNotNull { status ->
val tiers = proceedWithGettingTiers()
toMembershipStatus(status, tiers)
}
}
private suspend fun proceedWithGettingMembership(): Membership? {
val command = Command.Membership.GetStatus(
noCache = false
)
return repo.membershipStatus(command)
}
private suspend fun proceedWithGettingTiers(): List<MembershipTierData> {
val tiersParams = Command.Membership.GetTiers(
noCache = false,
locale = localeProvider.language() ?: DEFAULT_LOCALE
)
return repo.membershipGetTiers(tiersParams)
}
private fun toMembershipStatus(
membership: Membership?,
tiers: List<MembershipTierData>
): MembershipStatus {
return when (membership?.membershipStatusModel) {
STATUS_PENDING -> MembershipStatus.Pending
STATUS_PENDING_FINALIZATION -> MembershipStatus.Finalization
STATUS_ACTIVE -> toActiveMembershipStatus(membership, tiers)
STATUS_UNKNOWN, null -> {
Timber.e("Invalid or unknown membership status")
MembershipStatus.Unknown
}
else -> MembershipStatus.Unknown
}
}
private fun toActiveMembershipStatus(
membership: Membership,
tiers: List<MembershipTierData>
): MembershipStatus {
val tier = tiers.firstOrNull { it.id == membership.tier }
return if (tier != null) {
MembershipStatus.Active(
tier = tier,
status = membership.membershipStatusModel,
dateEnds = membership.dateEnds,
paymentMethod = membership.paymentMethod,
anyName = membership.requestedAnyName
)
} else {
Timber.e("Membership tier not found: ${membership.tier}")
MembershipStatus.Unknown
}
}
companion object {
const val DEFAULT_LOCALE = "en"
}
}
}