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

DROID-2899 Multiplayer | Enhancement | Support deeplink to object with invite to shared space (#1878)

This commit is contained in:
Evgenii Kozlov 2024-12-06 11:56:03 +01:00 committed by GitHub
parent 9b1e9bb23c
commit b6eab3aedc
Signed by: github
GPG key ID: B5690EEEBB952194
14 changed files with 229 additions and 41 deletions

View file

@ -1,6 +1,7 @@
package com.anytypeio.anytype.di.feature
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.domain.account.AccountStatusChannel
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
@ -14,6 +15,8 @@ import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.misc.LocaleProvider
import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.notifications.SystemNotificationService
import com.anytypeio.anytype.domain.platform.InitialParamsProvider
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscriptionManager
@ -22,6 +25,7 @@ import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
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.other.DefaultSpaceInviteResolver
import com.anytypeio.anytype.presentation.main.MainViewModelFactory
import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider
import com.anytypeio.anytype.presentation.navigation.DeepLinkToObjectDelegate
@ -70,7 +74,8 @@ object MainEntryModule {
deepLinkToObjectDelegate: DeepLinkToObjectDelegate,
awaitAccountStartManager: AwaitAccountStartManager,
membershipProvider: MembershipProvider,
globalSubscriptionManager: GlobalSubscriptionManager
globalSubscriptionManager: GlobalSubscriptionManager,
spaceInviteResolver: SpaceInviteResolver
): MainViewModelFactory = MainViewModelFactory(
resumeAccount = resumeAccount,
analytics = analytics,
@ -87,7 +92,8 @@ object MainEntryModule {
deepLinkToObjectDelegate = deepLinkToObjectDelegate,
awaitAccountStartManager = awaitAccountStartManager,
membershipProvider = membershipProvider,
globalSubscriptionManager = globalSubscriptionManager
globalSubscriptionManager = globalSubscriptionManager,
spaceInviteResolver = spaceInviteResolver
)
@JvmStatic
@ -192,4 +198,9 @@ object MainEntryModule {
fun provideDeepLinkToObjectDelegate(
default: DeepLinkToObjectDelegate.Default
): DeepLinkToObjectDelegate = default
@JvmStatic
@PerScreen
@Provides
fun provideSpaceInviteResolver(): SpaceInviteResolver = DefaultSpaceInviteResolver
}

View file

@ -15,6 +15,8 @@ import com.anytypeio.anytype.domain.dashboard.interactor.SetObjectListIsFavorite
import com.anytypeio.anytype.domain.misc.DateProvider
import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.GetSpaceInviteLink
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
import com.anytypeio.anytype.domain.objects.SetObjectListIsArchived
@ -119,7 +121,9 @@ object ObjectMenuModule {
payloadDelegator: PayloadDelegator,
setObjectListIsFavorite: SetObjectListIsFavorite,
setObjectIsArchived: SetObjectListIsArchived,
fieldParser: FieldParser
fieldParser: FieldParser,
spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
getSpaceInviteLink: GetSpaceInviteLink
): ObjectMenuViewModel.Factory = ObjectMenuViewModel.Factory(
setObjectIsArchived = setObjectIsArchived,
duplicateObject = duplicateObject,
@ -142,7 +146,9 @@ object ObjectMenuModule {
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
payloadDelegator = payloadDelegator,
setObjectListIsFavorite = setObjectListIsFavorite,
fieldParser = fieldParser
fieldParser = fieldParser,
getSpaceInviteLink = getSpaceInviteLink,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer
)
@JvmStatic
@ -237,6 +243,8 @@ object ObjectSetMenuModule {
setObjectListIsFavorite: SetObjectListIsFavorite,
setObjectIsArchived: SetObjectListIsArchived,
fieldParser: FieldParser,
getSpaceInviteLink: GetSpaceInviteLink,
spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
): ObjectSetMenuViewModel.Factory = ObjectSetMenuViewModel.Factory(
setObjectListIsArchived = setObjectIsArchived,
addBackLinkToObject = addBackLinkToObject,
@ -255,7 +263,9 @@ object ObjectSetMenuModule {
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
payloadDelegator = payloadDelegator,
setObjectListIsFavorite = setObjectListIsFavorite,
fieldParser = fieldParser
fieldParser = fieldParser,
getSpaceInviteLink = getSpaceInviteLink,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer
)
@JvmStatic

View file

@ -22,6 +22,7 @@ import com.anytypeio.anytype.domain.misc.AppActionManager
import com.anytypeio.anytype.domain.misc.DateProvider
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.`object`.GetObject
@ -38,6 +39,7 @@ import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
import com.anytypeio.anytype.domain.templates.GetTemplates
import com.anytypeio.anytype.domain.workspace.NotificationsChannel
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.other.DefaultSpaceInviteResolver
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
import com.anytypeio.anytype.presentation.common.PayloadDelegator
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
@ -207,6 +209,11 @@ object HomeScreenModule {
@PerScreen
fun coverHashProvider() : CoverImageHashProvider = DefaultCoverImageHashProvider()
@JvmStatic
@PerScreen
@Provides
fun provideSpaceInviteResolver(): SpaceInviteResolver = DefaultSpaceInviteResolver
@Module
interface Declarations {
@PerScreen

View file

@ -2,6 +2,7 @@ package com.anytypeio.anytype.di.feature.vault
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
@ -12,15 +13,18 @@ import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.misc.AppActionManager
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.other.DefaultSpaceInviteResolver
import com.anytypeio.anytype.presentation.navigation.DeepLinkToObjectDelegate
import com.anytypeio.anytype.presentation.vault.VaultViewModel
import com.anytypeio.anytype.ui.vault.VaultFragment
import dagger.Binds
import dagger.Component
import dagger.Module
import dagger.Provides
@Component(
dependencies = [VaultComponentDependencies::class],
@ -56,6 +60,10 @@ object VaultModule {
default: DeepLinkToObjectDelegate.Default
) : DeepLinkToObjectDelegate
}
@PerScreen
@Provides
fun provideSpaceInviteResolver() : SpaceInviteResolver = DefaultSpaceInviteResolver
}
interface VaultComponentDependencies : ComponentDependencies {

View file

@ -9,6 +9,8 @@ import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
const val DEEP_LINK_PATTERN = "anytype://"
const val DEEP_LINK_INVITE_DOMAIN = "invite.any.coop"
/**
* Regex pattern for matching
*/
@ -25,6 +27,8 @@ const val MEMBERSHIP_PATH = "membership"
const val TYPE_PARAM = "type"
const val OBJECT_ID_PARAM = "objectId"
const val SPACE_ID_PARAM = "spaceId"
const val CONTENT_ID_PARAM = "cid"
const val ENCRYPTION_KEY_PARAM = "key"
const val SOURCE_PARAM = "source"
const val TYPE_VALUE_EXPERIENCE = "experience"
const val TIER_ID_PARAM = "tier"
@ -61,9 +65,19 @@ object DefaultDeepLinkResolver : DeepLinkResolver {
val obj = uri.getQueryParameter(OBJECT_ID_PARAM)
val space = uri.getQueryParameter(SPACE_ID_PARAM)
if (!obj.isNullOrEmpty() && !space.isNullOrEmpty()) {
val cid = uri.getQueryParameter(CONTENT_ID_PARAM)
val key = uri.getQueryParameter(ENCRYPTION_KEY_PARAM)
DeepLinkResolver.Action.DeepLinkToObject(
obj = obj,
space = SpaceId(space)
space = SpaceId(space),
invite = if (!cid.isNullOrEmpty() && !key.isNullOrEmpty()) {
DeepLinkResolver.Action.DeepLinkToObject.Invite(
cid = cid,
key = key
)
} else {
null
}
)
} else {
DeepLinkResolver.Action.Unknown
@ -82,6 +96,15 @@ object DefaultDeepLinkResolver : DeepLinkResolver {
return "${DEEP_LINK_PATTERN}${OBJECT_PATH}?${OBJECT_ID_PARAM}=$obj&${SPACE_ID_PARAM}=${space.id}"
}
override fun createObjectDeepLinkWithInvite(
obj: Id,
space: SpaceId,
invite: Id,
encryptionKey: String
): Url {
return "${DEEP_LINK_PATTERN}${OBJECT_PATH}?${OBJECT_ID_PARAM}=$obj&${SPACE_ID_PARAM}=${space.id}&${DefaultSpaceInviteResolver.CONTENT_ID_KEY}=$invite&${DefaultSpaceInviteResolver.FILE_KEY_KEY}=$encryptionKey"
}
override fun isDeepLink(link: String): Boolean {
return link.contains(defaultInviteRegex) || link.contains(DEEP_LINK_PATTERN)
}
@ -112,8 +135,12 @@ object DefaultSpaceInviteResolver : SpaceInviteResolver {
}
}
override fun createInviteLink(contentId: String, encryptionKey: String) : String {
return "https://$DEEP_LINK_INVITE_DOMAIN/$contentId#$encryptionKey"
}
private const val CONTENT_INDEX = 1
private const val KEY_INDEX = 2
private const val CONTENT_ID_KEY = "cid"
private const val FILE_KEY_KEY = "key"
const val CONTENT_ID_KEY = "cid"
const val FILE_KEY_KEY = "key"
}

View file

@ -11,6 +11,13 @@ interface DeepLinkResolver {
fun createObjectDeepLink(obj: Id, space: SpaceId) : Url
fun createObjectDeepLinkWithInvite(
obj: Id,
space: SpaceId,
invite: Id,
encryptionKey: String
) : Url
fun isDeepLink(link: String) : Boolean
sealed class Action {
@ -21,8 +28,14 @@ interface DeepLinkResolver {
data class Invite(val link: String) : Action()
data class DeepLinkToObject(
val obj: Id,
val space: SpaceId
) : Action()
val space: SpaceId,
val invite: Invite? = null
) : Action() {
data class Invite(
val cid: String,
val key: String
)
}
data class DeepLinkToMembership(
val tierId: String?
) : Action()

View file

@ -5,4 +5,5 @@ import com.anytypeio.anytype.core_models.Id
interface SpaceInviteResolver {
fun parseContentId(link: String) : Id?
fun parseFileKey(link: String) : Id?
fun createInviteLink(contentId: String, encryptionKey: String) : String
}

View file

@ -54,6 +54,7 @@ import com.anytypeio.anytype.domain.misc.DateProvider
import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.misc.Reducer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.`object`.GetObject
import com.anytypeio.anytype.domain.`object`.OpenObject
@ -207,7 +208,8 @@ class HomeScreenViewModel(
private val clearLastOpenedObject: ClearLastOpenedObject,
private val spaceBinWidgetContainer: SpaceBinWidgetContainer,
private val featureToggles: FeatureToggles,
private val fieldParser: FieldParser
private val fieldParser: FieldParser,
private val spaceInviteResolver: SpaceInviteResolver
) : NavigationViewModel<HomeScreenViewModel.Navigation>(),
Reducer<ObjectView, Payload>,
WidgetActiveViewStateHolder by widgetActiveViewStateHolder,
@ -1339,7 +1341,19 @@ class HomeScreenViewModel(
).collect { result ->
when(result) {
is DeepLinkToObjectDelegate.Result.Error -> {
commands.emit(Command.Deeplink.DeepLinkToObjectNotWorking)
val link = deeplink.invite
if (link != null) {
commands.emit(
Command.Deeplink.Invite(
link = spaceInviteResolver.createInviteLink(
contentId = link.cid,
encryptionKey = link.key
)
)
)
} else {
commands.emit(Command.Deeplink.DeepLinkToObjectNotWorking)
}
}
is DeepLinkToObjectDelegate.Result.Success -> {
proceedWithNavigation(result.obj.navigation())
@ -2196,7 +2210,8 @@ class HomeScreenViewModel(
private val clearLastOpenedObject: ClearLastOpenedObject,
private val spaceBinWidgetContainer: SpaceBinWidgetContainer,
private val featureToggles: FeatureToggles,
private val fieldParser: FieldParser
private val fieldParser: FieldParser,
private val spaceInviteResolver: SpaceInviteResolver
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T = HomeScreenViewModel(
@ -2248,7 +2263,8 @@ class HomeScreenViewModel(
clearLastOpenedObject = clearLastOpenedObject,
spaceBinWidgetContainer = spaceBinWidgetContainer,
featureToggles = featureToggles,
fieldParser = fieldParser
fieldParser = fieldParser,
spaceInviteResolver = spaceInviteResolver
) as T
}

View file

@ -24,6 +24,7 @@ import com.anytypeio.anytype.domain.base.Interactor
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.misc.LocaleProvider
import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
import com.anytypeio.anytype.domain.notifications.SystemNotificationService
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscriptionManager
import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
@ -62,7 +63,8 @@ class MainViewModel(
private val deepLinkToObjectDelegate: DeepLinkToObjectDelegate,
private val awaitAccountStartManager: AwaitAccountStartManager,
private val membershipProvider: MembershipProvider,
private val globalSubscriptionManager: GlobalSubscriptionManager
private val globalSubscriptionManager: GlobalSubscriptionManager,
private val spaceInviteResolver: SpaceInviteResolver
) : ViewModel(),
NotificationActionDelegate by notificationActionDelegate,
DeepLinkToObjectDelegate by deepLinkToObjectDelegate {
@ -336,7 +338,19 @@ class MainViewModel(
)
when (result) {
is DeepLinkToObjectDelegate.Result.Error -> {
toasts.emit("Error: $result")
val link = deeplink.invite
if (link != null) {
commands.emit(
Command.Deeplink.Invite(
spaceInviteResolver.createInviteLink(
contentId = link.cid,
encryptionKey = link.key
)
)
)
} else {
toasts.emit("Error: $result")
}
}
is DeepLinkToObjectDelegate.Result.Success -> {
commands.emit(

View file

@ -10,6 +10,7 @@ import com.anytypeio.anytype.domain.auth.interactor.Logout
import com.anytypeio.anytype.domain.auth.interactor.ResumeAccount
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.misc.LocaleProvider
import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
import com.anytypeio.anytype.domain.notifications.SystemNotificationService
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscriptionManager
import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
@ -36,7 +37,8 @@ class MainViewModelFactory @Inject constructor(
private val deepLinkToObjectDelegate: DeepLinkToObjectDelegate,
private val awaitAccountStartManager: AwaitAccountStartManager,
private val membershipProvider: MembershipProvider,
private val globalSubscriptionManager: GlobalSubscriptionManager
private val globalSubscriptionManager: GlobalSubscriptionManager,
private val spaceInviteResolver: SpaceInviteResolver
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
@ -57,6 +59,7 @@ class MainViewModelFactory @Inject constructor(
deepLinkToObjectDelegate = deepLinkToObjectDelegate,
awaitAccountStartManager = awaitAccountStartManager,
membershipProvider = membershipProvider,
globalSubscriptionManager = globalSubscriptionManager
globalSubscriptionManager = globalSubscriptionManager,
spaceInviteResolver = spaceInviteResolver
) as T
}

View file

@ -38,6 +38,9 @@ import com.anytypeio.anytype.presentation.extension.sendAnalyticsDefaultTemplate
import com.anytypeio.anytype.presentation.objects.ObjectAction
import com.anytypeio.anytype.core_models.SupportedLayouts.fileLayouts
import com.anytypeio.anytype.core_models.SupportedLayouts.systemLayouts
import com.anytypeio.anytype.core_models.multiplayer.SpaceAccessType
import com.anytypeio.anytype.domain.multiplayer.GetSpaceInviteLink
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.presentation.objects.isTemplatesAllowed
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.presentation.util.downloader.DebugGoroutinesShareDownloader
@ -69,7 +72,9 @@ class ObjectMenuViewModel(
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
private val setObjectListIsFavorite: SetObjectListIsFavorite,
private val setObjectIsArchived: SetObjectListIsArchived,
private val fieldParser: FieldParser
private val fieldParser: FieldParser,
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
private val getSpaceInviteLink: GetSpaceInviteLink
) : ObjectMenuViewModelBase(
setObjectIsArchived = setObjectIsArchived,
addBackLinkToObject = addBackLinkToObject,
@ -86,7 +91,10 @@ class ObjectMenuViewModel(
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
payloadDelegator = payloadDelegator,
setObjectListIsFavorite = setObjectListIsFavorite,
fieldParser = fieldParser
fieldParser = fieldParser,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer,
deepLinkResolver = deepLinkResolver,
getSpaceInviteLink = getSpaceInviteLink
) {
init {
@ -276,11 +284,13 @@ class ObjectMenuViewModel(
proceedWithLinkTo()
}
ObjectAction.COPY_LINK -> {
val deeplink = deepLinkResolver.createObjectDeepLink(
obj = ctx,
space = SpaceId(space)
)
viewModelScope.launch { commands.emit(Command.ShareDeeplinkToObject(deeplink)) }
viewModelScope.launch {
val link = proceedWithGeneratingObjectLink(
space = SpaceId(space),
ctx = ctx
)
commands.emit(Command.ShareDeeplinkToObject(link))
}
}
ObjectAction.UNLOCK -> {
proceedWithUpdatingLockStatus(ctx, false)
@ -479,7 +489,9 @@ class ObjectMenuViewModel(
private val payloadDelegator: PayloadDelegator,
private val setObjectListIsFavorite: SetObjectListIsFavorite,
private val setObjectIsArchived: SetObjectListIsArchived,
private val fieldParser: FieldParser
private val fieldParser: FieldParser,
private val getSpaceInviteLink: GetSpaceInviteLink,
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ObjectMenuViewModel(
@ -504,7 +516,9 @@ class ObjectMenuViewModel(
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
payloadDelegator = payloadDelegator,
setObjectListIsFavorite = setObjectListIsFavorite,
fieldParser = fieldParser
fieldParser = fieldParser,
getSpaceInviteLink = getSpaceInviteLink,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer
) as T
}
}

View file

@ -11,11 +11,15 @@ import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_models.WidgetLayout
import com.anytypeio.anytype.core_models.isDataView
import com.anytypeio.anytype.core_models.multiplayer.SpaceAccessType
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.fold
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
import com.anytypeio.anytype.domain.dashboard.interactor.SetObjectListIsFavorite
import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.GetSpaceInviteLink
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.objects.SetObjectListIsArchived
import com.anytypeio.anytype.domain.page.AddBackLinkToObject
@ -62,7 +66,10 @@ abstract class ObjectMenuViewModelBase(
private val payloadDelegator: PayloadDelegator,
private val setObjectListIsFavorite: SetObjectListIsFavorite,
private val setObjectIsArchived: SetObjectListIsArchived,
private val fieldParser: FieldParser
private val fieldParser: FieldParser,
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
private val getSpaceInviteLink: GetSpaceInviteLink,
private val deepLinkResolver: DeepLinkResolver
) : BaseViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate {
protected val jobs = mutableListOf<Job>()
@ -434,6 +441,34 @@ abstract class ObjectMenuViewModelBase(
}
}
suspend fun proceedWithGeneratingObjectLink(
space: SpaceId,
ctx: String
): String {
val spaceView = spaceViewSubscriptionContainer.get(space)
return if (spaceView?.spaceAccessType == SpaceAccessType.SHARED) {
val link = getSpaceInviteLink.async(space).getOrNull()
if (link != null) {
deepLinkResolver.createObjectDeepLinkWithInvite(
obj = ctx,
space = space,
encryptionKey = link.fileKey,
invite = link.contentId
)
} else {
deepLinkResolver.createObjectDeepLink(
obj = ctx,
space = space
)
}
} else {
deepLinkResolver.createObjectDeepLink(
obj = ctx,
space = space
)
}
}
sealed class Command {
data object OpenObjectIcons : Command()
data object OpenSetIcons : Command()

View file

@ -13,6 +13,8 @@ import com.anytypeio.anytype.domain.collections.AddObjectToCollection
import com.anytypeio.anytype.domain.dashboard.interactor.SetObjectListIsFavorite
import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.GetSpaceInviteLink
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.objects.SetObjectListIsArchived
import com.anytypeio.anytype.domain.page.AddBackLinkToObject
@ -51,7 +53,9 @@ class ObjectSetMenuViewModel(
private val deepLinkResolver: DeepLinkResolver,
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
setObjectListIsFavorite: SetObjectListIsFavorite,
fieldParser: FieldParser
fieldParser: FieldParser,
spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
getSpaceInviteLink: GetSpaceInviteLink
) : ObjectMenuViewModelBase(
setObjectIsArchived = setObjectIsArchived,
addBackLinkToObject = addBackLinkToObject,
@ -68,7 +72,10 @@ class ObjectSetMenuViewModel(
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
payloadDelegator = payloadDelegator,
setObjectListIsFavorite = setObjectListIsFavorite,
fieldParser = fieldParser
fieldParser = fieldParser,
deepLinkResolver = deepLinkResolver,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer,
getSpaceInviteLink = getSpaceInviteLink
) {
init {
@ -94,7 +101,9 @@ class ObjectSetMenuViewModel(
private val payloadDelegator: PayloadDelegator,
private val setObjectListIsFavorite: SetObjectListIsFavorite,
private val setObjectListIsArchived: SetObjectListIsArchived,
private val fieldParser: FieldParser
private val fieldParser: FieldParser,
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
private val getSpaceInviteLink: GetSpaceInviteLink
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ObjectSetMenuViewModel(
@ -115,7 +124,9 @@ class ObjectSetMenuViewModel(
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
payloadDelegator = payloadDelegator,
setObjectListIsFavorite = setObjectListIsFavorite,
fieldParser = fieldParser
fieldParser = fieldParser,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer,
getSpaceInviteLink = getSpaceInviteLink
) as T
}
}
@ -219,11 +230,13 @@ class ObjectSetMenuViewModel(
proceedWithCreatingWidget(obj = wrapper)
}
ObjectAction.COPY_LINK -> {
val deeplink = deepLinkResolver.createObjectDeepLink(
obj = ctx,
space = SpaceId(space)
)
viewModelScope.launch { commands.emit(Command.ShareDeeplinkToObject(deeplink)) }
viewModelScope.launch {
val link = proceedWithGeneratingObjectLink(
space = SpaceId(space),
ctx = ctx
)
commands.emit(Command.ShareDeeplinkToObject(link))
}
}
ObjectAction.MOVE_TO,
ObjectAction.SEARCH_ON_PAGE,

View file

@ -20,6 +20,7 @@ import com.anytypeio.anytype.domain.base.onSuccess
import com.anytypeio.anytype.domain.misc.AppActionManager
import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.spaces.SaveCurrentSpace
import com.anytypeio.anytype.domain.vault.GetVaultSettings
@ -60,7 +61,8 @@ class VaultViewModel(
private val setVaultSpaceOrder: SetVaultSpaceOrder,
private val analytics: Analytics,
private val deepLinkToObjectDelegate: DeepLinkToObjectDelegate,
private val appActionManager: AppActionManager
private val appActionManager: AppActionManager,
private val spaceInviteResolver: SpaceInviteResolver
) : NavigationViewModel<VaultViewModel.Navigation>(), DeepLinkToObjectDelegate by deepLinkToObjectDelegate {
val spaces = MutableStateFlow<List<VaultSpaceView>>(emptyList())
@ -206,7 +208,19 @@ class VaultViewModel(
).collect { result ->
when(result) {
is DeepLinkToObjectDelegate.Result.Error -> {
commands.emit(Command.Deeplink.DeepLinkToObjectNotWorking)
val link = deeplink.invite
if (link != null) {
commands.emit(
Command.Deeplink.Invite(
link = spaceInviteResolver.createInviteLink(
contentId = link.cid,
encryptionKey = link.key
)
)
)
} else {
commands.emit(Command.Deeplink.DeepLinkToObjectNotWorking)
}
}
is DeepLinkToObjectDelegate.Result.Success -> {
proceedWithNavigation(result.obj.navigation())
@ -304,7 +318,8 @@ class VaultViewModel(
private val observeVaultSettings: ObserveVaultSettings,
private val analytics: Analytics,
private val deepLinkToObjectDelegate: DeepLinkToObjectDelegate,
private val appActionManager: AppActionManager
private val appActionManager: AppActionManager,
private val spaceInviteResolver: SpaceInviteResolver
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
@ -321,7 +336,8 @@ class VaultViewModel(
observeVaultSettings = observeVaultSettings,
analytics = analytics,
deepLinkToObjectDelegate = deepLinkToObjectDelegate,
appActionManager = appActionManager
appActionManager = appActionManager,
spaceInviteResolver = spaceInviteResolver
) as T
}