diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt index a3aa4f384c..c3f4bb3f8e 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt @@ -19,6 +19,7 @@ import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionCon import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.payments.GetMembershipStatus +import com.anytypeio.anytype.domain.search.SubscriptionEventChannel import com.anytypeio.anytype.domain.workspace.SpaceManager import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider @@ -119,4 +120,5 @@ interface SpaceSettingsDependencies : ComponentDependencies { fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer fun activeSpaceMemberSubscriptionContainer(): ActiveSpaceMemberSubscriptionContainer fun analyticSpaceHelper(): AnalyticSpaceHelperDelegate + fun subscriptionEventChannel(): SubscriptionEventChannel } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt index 4ba828e805..8a08c47325 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt @@ -203,6 +203,11 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment() { skipCollapsed() } + override fun onStop() { + super.onStop() + vm.onStop() + } + override fun injectDependencies() { componentManager().spaceSettingsComponent.get(SpaceId(space)).inject(this) } diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetProfile.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetProfile.kt index 228c9d24e6..99c9c141d4 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetProfile.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetProfile.kt @@ -4,12 +4,14 @@ import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.SubscriptionEvent import com.anytypeio.anytype.core_models.primitives.SpaceId +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.`object`.amend import com.anytypeio.anytype.domain.`object`.unset import com.anytypeio.anytype.domain.base.BaseUseCase import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.search.SubscriptionEventChannel +import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -17,17 +19,25 @@ import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.scan +import kotlinx.coroutines.withContext /** Use case for getting currently selected user account. */ -class GetProfile( + class GetProfile @Inject constructor( private val provider: ConfigStorage, private val repo: BlockRepository, - private val channel: SubscriptionEventChannel + private val channel: SubscriptionEventChannel, + private val dispatchers: AppCoroutineDispatchers ) : BaseUseCase() { fun subscribe(subscription: Id) = channel.subscribe(subscriptions = listOf(subscription)) + suspend fun unsubscribe(subscription: Id) = withContext(dispatchers.io) { + repo.cancelObjectSearchSubscription( + subscriptions = listOf(subscription) + ) + } + fun observe( subscription: Id, keys: List, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainer.kt index 79eaeebd3c..73f4fd794e 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainer.kt @@ -179,11 +179,10 @@ interface SpaceViewSubscriptionContainer { } } -@Deprecated("To de deleted") -fun SpaceViewSubscriptionContainer.isSharingLimitReached( +fun SpaceViewSubscriptionContainer.sharedSpacesCount( spaceToUserPermissions: Flow> -) : Flow> { - val sharedSpacesCount = combine( +) : Flow { + return combine( observe(), spaceToUserPermissions ) { spaceViews, permissions -> @@ -192,17 +191,4 @@ fun SpaceViewSubscriptionContainer.isSharingLimitReached( spaceView.spaceAccessType == SHARED && permission == OWNER } } - val sharedSpaceLimit = observe().map { spaceViews -> - val defaultSpace = spaceViews.firstOrNull { space -> - space.spaceAccessType == SpaceAccessType.DEFAULT - } - defaultSpace?.sharedSpaceLimit ?: 0 - } - return combine( - sharedSpaceLimit, - sharedSpacesCount - ) { limit, count -> - val isLimitReached = limit == 0 || count >= limit - Pair(isLimitReached, limit) - } } \ No newline at end of file diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainerTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainerTest.kt index e38ac5d8b9..3e7f6c9bd6 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainerTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainerTest.kt @@ -51,7 +51,7 @@ class SpaceViewSubscriptionContainerTest { ) } - container.isSharingLimitReached(flowOf(permissions)).test { + container.sharedSpacesCount(flowOf(permissions)).test { val result = awaitItem() assertEquals( expected = true, @@ -91,7 +91,7 @@ class SpaceViewSubscriptionContainerTest { ) } - container.isSharingLimitReached(flowOf(permissions)).test { + container.sharedSpacesCount(flowOf(permissions)).test { val result = awaitItem() assertEquals( expected = false, @@ -131,7 +131,7 @@ class SpaceViewSubscriptionContainerTest { ) } - container.isSharingLimitReached(flowOf(permissions)).test { + container.sharedSpacesCount(flowOf(permissions)).test { val result = awaitItem() assertEquals( expected = true, @@ -171,7 +171,7 @@ class SpaceViewSubscriptionContainerTest { ) } - container.isSharingLimitReached(flowOf(permissions)).test { + container.sharedSpacesCount(flowOf(permissions)).test { val result = awaitItem() assertEquals( expected = false, @@ -211,7 +211,7 @@ class SpaceViewSubscriptionContainerTest { ) } - container.isSharingLimitReached(flowOf(permissions)).test { + container.sharedSpacesCount(flowOf(permissions)).test { val result = awaitItem() assertEquals( expected = false, @@ -251,7 +251,7 @@ class SpaceViewSubscriptionContainerTest { ) } - container.isSharingLimitReached(flowOf(permissions)).test { + container.sharedSpacesCount(flowOf(permissions)).test { val result = awaitItem() assertEquals( expected = true, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt index 4ab8f732a6..b967bd2421 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt @@ -25,26 +25,29 @@ import com.anytypeio.anytype.core_models.multiplayer.SpaceAccessType import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_utils.ui.ViewState +import com.anytypeio.anytype.domain.auth.interactor.GetProfile import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.debugging.DebugSpaceShareDownloader -import com.anytypeio.anytype.domain.icon.SetDocumentImageIcon -import com.anytypeio.anytype.domain.icon.SetImageIcon +import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams +import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.media.UploadFile import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider -import com.anytypeio.anytype.domain.multiplayer.isSharingLimitReached +import com.anytypeio.anytype.domain.multiplayer.sharedSpacesCount import com.anytypeio.anytype.domain.payments.GetMembershipStatus import com.anytypeio.anytype.domain.spaces.DeleteSpace import com.anytypeio.anytype.domain.spaces.SetSpaceDetails import com.anytypeio.anytype.domain.workspace.SpaceManager import com.anytypeio.anytype.presentation.common.BaseViewModel +import com.anytypeio.anytype.presentation.home.HomeScreenViewModel.Companion.HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION import javax.inject.Inject import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import timber.log.Timber @@ -63,7 +66,8 @@ class SpaceSettingsViewModel( private val spaceViewContainer: SpaceViewSubscriptionContainer, private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer, private val getMembership: GetMembershipStatus, - private val uploadFile: UploadFile + private val uploadFile: UploadFile, + private val container: StorelessSubscriptionContainer ): BaseViewModel() { val commands = MutableSharedFlow() @@ -86,11 +90,44 @@ class SpaceSettingsViewModel( private fun proceedWithObservingSpaceView() { viewModelScope.launch { val config = spaceManager.getConfig(params.space) + + container.subscribe( + StoreSearchByIdsParams( + space = SpaceId(config!!.techSpace), + subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, + targets = listOf(config!!.profile), + keys = listOf( + Relations.ID, + Relations.SHARED_SPACES_LIMIT + ) + ) + ) + val sharedSpacesLimit = container.subscribe( + StoreSearchByIdsParams( + space = SpaceId(config!!.techSpace), + subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, + targets = listOf(config!!.profile), + keys = listOf( + Relations.ID, + Relations.SHARED_SPACES_LIMIT + ) + ) + ).map { results -> + results.firstOrNull()?.let { + it.getValue(Relations.SHARED_SPACES_LIMIT)?.toInt() ?: 0 + } ?: 0 + } + + val sharedSpacesCount = spaceViewContainer.sharedSpacesCount( + userPermissionProvider.all() + ) + combine( spaceViewContainer.observe(params.space), userPermissionProvider.observe(params.space), - spaceViewContainer.isSharingLimitReached(userPermissionProvider.all()) - ) { spaceView, permission, shareLimitReached -> + sharedSpacesLimit, + sharedSpacesCount + ) { spaceView, permission, sharedSpacesLimit, sharedSpacesCount -> val store = activeSpaceMemberSubscriptionContainer.get(params.space) val requests: Int = if (store is ActiveSpaceMemberSubscriptionContainer.Store.Data) { store.members.count { it.status == ParticipantStatus.JOINING } @@ -119,8 +156,8 @@ class SpaceSettingsViewModel( spaceType = spaceView.spaceAccessType?.asSpaceType() ?: UNKNOWN_SPACE_TYPE, permissions = permission ?: SpaceMemberPermissions.NO_PERMISSIONS, shareLimitReached = ShareLimitsState( - shareLimitReached = shareLimitReached.first, - sharedSpacesLimit = shareLimitReached.second + shareLimitReached = sharedSpacesCount >= sharedSpacesLimit, + sharedSpacesLimit = sharedSpacesLimit ), requests = requests ) @@ -161,7 +198,11 @@ class SpaceSettingsViewModel( } fun onStop() { - // TODO unsubscribe + viewModelScope.launch { + container.unsubscribe( + listOf(SPACE_SETTINGS_PROFILE_SUBSCRIPTION) + ) + } } fun onSpaceDebugClicked() { @@ -403,7 +444,7 @@ class SpaceSettingsViewModel( class Factory @Inject constructor( private val params: Params, private val analytics: Analytics, - private val container: SpaceViewSubscriptionContainer, + private val spaceViewsContainer: SpaceViewSubscriptionContainer, private val urlBuilder: UrlBuilder, private val setSpaceDetails: SetSpaceDetails, private val gradientProvider: SpaceGradientProvider, @@ -415,13 +456,14 @@ class SpaceSettingsViewModel( private val userPermissionProvider: UserPermissionProvider, private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer, private val getMembership: GetMembershipStatus, - private val uploadFile: UploadFile + private val uploadFile: UploadFile, + private val container: StorelessSubscriptionContainer ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create( modelClass: Class ): T = SpaceSettingsViewModel( - spaceViewContainer = container, + spaceViewContainer = spaceViewsContainer, urlBuilder = urlBuilder, spaceManager = spaceManager, setSpaceDetails = setSpaceDetails, @@ -435,7 +477,8 @@ class SpaceSettingsViewModel( userPermissionProvider = userPermissionProvider, activeSpaceMemberSubscriptionContainer = activeSpaceMemberSubscriptionContainer, getMembership = getMembership, - uploadFile = uploadFile + uploadFile = uploadFile, + container = container ) as T } @@ -443,5 +486,6 @@ class SpaceSettingsViewModel( companion object { const val SPACE_DEBUG_MSG = "Kindly share this debug logs with Anytype developers." + const val SPACE_SETTINGS_PROFILE_SUBSCRIPTION = "space.settings.profile-subscription" } } \ No newline at end of file