mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2258 Multiplayer | Enhancement | UX and API for the request-to-join-space flow (#946)
This commit is contained in:
parent
ccc23c62d6
commit
eb64b68503
13 changed files with 528 additions and 64 deletions
|
@ -63,6 +63,7 @@ import com.anytypeio.anytype.di.feature.cover.UnsplashModule
|
|||
import com.anytypeio.anytype.di.feature.home.DaggerHomeScreenComponent
|
||||
import com.anytypeio.anytype.di.feature.library.DaggerLibraryComponent
|
||||
import com.anytypeio.anytype.di.feature.multiplayer.DaggerShareSpaceComponent
|
||||
import com.anytypeio.anytype.di.feature.multiplayer.DaggerSpaceJoinRequestComponent
|
||||
import com.anytypeio.anytype.di.feature.objects.DaggerSelectObjectTypeComponent
|
||||
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingComponent
|
||||
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingStartComponent
|
||||
|
@ -104,6 +105,7 @@ import com.anytypeio.anytype.di.feature.widgets.SelectWidgetSourceModule
|
|||
import com.anytypeio.anytype.di.feature.widgets.SelectWidgetTypeModule
|
||||
import com.anytypeio.anytype.di.main.MainComponent
|
||||
import com.anytypeio.anytype.presentation.multiplayer.ShareSpaceViewModel
|
||||
import com.anytypeio.anytype.presentation.multiplayer.SpaceJoinRequestViewModel
|
||||
import com.anytypeio.anytype.presentation.objects.SelectObjectTypeViewModel
|
||||
import com.anytypeio.anytype.presentation.relations.option.CreateOrEditOptionViewModel
|
||||
import com.anytypeio.anytype.presentation.relations.value.attachment.AttachmentValueViewModel
|
||||
|
@ -1047,6 +1049,14 @@ class ComponentManager(
|
|||
.build()
|
||||
}
|
||||
|
||||
val spaceJoinRequestComponent = ComponentWithParams { params: SpaceJoinRequestViewModel.Params ->
|
||||
DaggerSpaceJoinRequestComponent
|
||||
.builder()
|
||||
.withDependencies(findComponentDependencies())
|
||||
.withParams(params = params)
|
||||
.build()
|
||||
}
|
||||
|
||||
class Component<T>(private val builder: () -> T) {
|
||||
|
||||
private var instance: T? = null
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package com.anytypeio.anytype.di.feature.multiplayer
|
||||
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
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.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
import com.anytypeio.anytype.presentation.multiplayer.SpaceJoinRequestViewModel
|
||||
import com.anytypeio.anytype.ui.multiplayer.SpaceJoinRequestFragment
|
||||
import dagger.Binds
|
||||
import dagger.BindsInstance
|
||||
import dagger.Component
|
||||
import dagger.Module
|
||||
|
||||
@Component(
|
||||
dependencies = [SpaceJoinRequestDependencies::class],
|
||||
modules = [
|
||||
SpaceJoinRequestModule::class,
|
||||
SpaceJoinRequestModule.Declarations::class
|
||||
]
|
||||
)
|
||||
@PerDialog
|
||||
interface SpaceJoinRequestComponent {
|
||||
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
fun withDependencies(dependencies: SpaceJoinRequestDependencies): Builder
|
||||
@BindsInstance
|
||||
fun withParams(params: SpaceJoinRequestViewModel.Params): Builder
|
||||
fun build(): SpaceJoinRequestComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: SpaceJoinRequestFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object SpaceJoinRequestModule {
|
||||
|
||||
@Module
|
||||
interface Declarations {
|
||||
@PerScreen
|
||||
@Binds
|
||||
fun bindViewModelFactory(factory: SpaceJoinRequestViewModel.Factory): ViewModelProvider.Factory
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface SpaceJoinRequestDependencies : ComponentDependencies {
|
||||
fun blockRepository(): BlockRepository
|
||||
fun urlBuilder(): UrlBuilder
|
||||
fun dispatchers(): AppCoroutineDispatchers
|
||||
fun spaceManager(): SpaceManager
|
||||
}
|
|
@ -22,6 +22,7 @@ import com.anytypeio.anytype.di.feature.auth.DeletedAccountDependencies
|
|||
import com.anytypeio.anytype.di.feature.home.HomeScreenDependencies
|
||||
import com.anytypeio.anytype.di.feature.library.LibraryDependencies
|
||||
import com.anytypeio.anytype.di.feature.multiplayer.ShareSpaceDependencies
|
||||
import com.anytypeio.anytype.di.feature.multiplayer.SpaceJoinRequestDependencies
|
||||
import com.anytypeio.anytype.di.feature.objects.SelectObjectTypeDependencies
|
||||
import com.anytypeio.anytype.di.feature.onboarding.OnboardingDependencies
|
||||
import com.anytypeio.anytype.di.feature.onboarding.OnboardingStartDependencies
|
||||
|
@ -106,7 +107,9 @@ interface MainComponent :
|
|||
SpacesStorageDependencies,
|
||||
AppPreferencesDependencies,
|
||||
AddToAnytypeDependencies,
|
||||
ShareSpaceDependencies {
|
||||
ShareSpaceDependencies,
|
||||
SpaceJoinRequestDependencies
|
||||
{
|
||||
|
||||
fun inject(app: AndroidApplication)
|
||||
|
||||
|
@ -286,4 +289,9 @@ private abstract class ComponentDependenciesModule private constructor() {
|
|||
@IntoMap
|
||||
@ComponentDependenciesKey(ShareSpaceDependencies::class)
|
||||
abstract fun provideShareSpaceDependencies(component: MainComponent): ComponentDependencies
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ComponentDependenciesKey(SpaceJoinRequestDependencies::class)
|
||||
abstract fun provideSpaceJoinRequestDependencies(component: MainComponent): ComponentDependencies
|
||||
}
|
|
@ -12,6 +12,8 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
|
|||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_ui.features.multiplayer.ShareSpaceScreen
|
||||
import com.anytypeio.anytype.core_utils.ext.arg
|
||||
|
@ -45,16 +47,18 @@ class ShareSpaceFragment : BaseBottomSheetComposeFragment() {
|
|||
onRegenerateInviteLinkClicked = vm::onRegenerateInviteLinkClicked,
|
||||
onShareInviteLinkClicked = vm::onShareInviteLinkClicked,
|
||||
members = vm.members.collectAsStateWithLifecycle().value,
|
||||
onRequestAction = {
|
||||
toast("TODO")
|
||||
}
|
||||
onViewRequestClicked = vm::onViewRequestClicked,
|
||||
onApproveUnjoinRequestClicked = vm::onApproveUnjoinRequestClicked
|
||||
)
|
||||
LaunchedEffect(Unit) {
|
||||
vm.commands.collect { command ->
|
||||
proceedWithCommand(command)
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
vm.commands.collect { command ->
|
||||
proceedWithCommand(command)
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
vm.toasts.collect { toast(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +79,15 @@ class ShareSpaceFragment : BaseBottomSheetComposeFragment() {
|
|||
}
|
||||
startActivity(Intent.createChooser(intent, null))
|
||||
}
|
||||
is ShareSpaceViewModel.Command.ViewJoinRequest -> {
|
||||
findNavController().navigate(
|
||||
resId = R.id.spaceJoinRequestScreen,
|
||||
args = SpaceJoinRequestFragment.args(
|
||||
space = command.space,
|
||||
member = command.member
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package com.anytypeio.anytype.ui.multiplayer
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_ui.features.multiplayer.SpaceJoinRequestScreen
|
||||
import com.anytypeio.anytype.core_utils.ext.arg
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.multiplayer.SpaceJoinRequestViewModel
|
||||
import com.anytypeio.anytype.ui.settings.typography
|
||||
import javax.inject.Inject
|
||||
|
||||
class SpaceJoinRequestFragment : BaseBottomSheetComposeFragment() {
|
||||
|
||||
private val space get() = arg<Id>(SPACE_ID_KEY)
|
||||
private val member get() = arg<Id>(MEMBER_ID_KEY)
|
||||
|
||||
@Inject
|
||||
lateinit var factory: SpaceJoinRequestViewModel.Factory
|
||||
|
||||
private val vm by viewModels<SpaceJoinRequestViewModel> { factory }
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setContent {
|
||||
MaterialTheme(typography = typography) {
|
||||
when(val state = vm.viewState.collectAsStateWithLifecycle().value) {
|
||||
SpaceJoinRequestViewModel.ViewState.Error -> {
|
||||
// TODO Send toast.
|
||||
}
|
||||
SpaceJoinRequestViewModel.ViewState.Init -> {
|
||||
// Draw nothing.
|
||||
}
|
||||
is SpaceJoinRequestViewModel.ViewState.Success -> {
|
||||
SpaceJoinRequestScreen(
|
||||
state = state,
|
||||
onAddViewerClicked = vm::onJoinAsReaderClicked,
|
||||
onAddEditorClicked = vm::onJoinAsEditorClicked,
|
||||
onRejectClicked = vm::onRejectRequestClicked
|
||||
)
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
vm.toasts.collect { toast(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().spaceJoinRequestComponent.get(
|
||||
SpaceJoinRequestViewModel.Params(
|
||||
space = SpaceId(
|
||||
space
|
||||
), member = member
|
||||
)
|
||||
).inject(fragment = this)
|
||||
}
|
||||
|
||||
override fun releaseDependencies() {
|
||||
componentManager().spaceJoinRequestComponent.release()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SPACE_ID_KEY = "arg.space-join-request.space-id-key"
|
||||
const val MEMBER_ID_KEY = "arg.space-join-request.member-id-key"
|
||||
fun args(
|
||||
space: SpaceId,
|
||||
member: Id
|
||||
): Bundle = bundleOf(
|
||||
SPACE_ID_KEY to space.id,
|
||||
MEMBER_ID_KEY to member
|
||||
)
|
||||
}
|
||||
}
|
|
@ -538,4 +538,8 @@
|
|||
android:id="@+id/shareSpaceScreen"
|
||||
android:name="com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment"/>
|
||||
|
||||
<dialog
|
||||
android:id="@+id/spaceJoinRequestScreen"
|
||||
android:name="com.anytypeio.anytype.ui.multiplayer.SpaceJoinRequestFragment"/>
|
||||
|
||||
</navigation>
|
|
@ -317,6 +317,7 @@ sealed class ObjectWrapper {
|
|||
private val default = map.withDefault { null }
|
||||
|
||||
val id: Id by default
|
||||
val identity: Id by default
|
||||
val name: String? by default
|
||||
|
||||
val status
|
||||
|
|
|
@ -32,7 +32,7 @@ import com.anytypeio.anytype.core_ui.views.ButtonSecondary
|
|||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonWarning
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
|
||||
import com.anytypeio.anytype.presentation.multiplayer.SpaceJoinRequestView
|
||||
import com.anytypeio.anytype.presentation.multiplayer.SpaceJoinRequestViewModel.ViewState
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
|
@ -41,17 +41,16 @@ fun SpaceJoinRequestScreenPreview() {
|
|||
onAddEditorClicked = {},
|
||||
onAddViewerClicked = {},
|
||||
onRejectClicked = {},
|
||||
spaceJoinRequestView = SpaceJoinRequestView(
|
||||
state = ViewState.Success(
|
||||
memberName = "Merk",
|
||||
spaceName = "Investors",
|
||||
comment = "Hi Zhanna. It’s Merk, you sent me the link. Have a great day."
|
||||
spaceName = "Investors"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SpaceJoinRequestScreen(
|
||||
spaceJoinRequestView: SpaceJoinRequestView,
|
||||
state: ViewState.Success,
|
||||
onAddViewerClicked: () -> Unit,
|
||||
onAddEditorClicked: () -> Unit,
|
||||
onRejectClicked: () -> Unit,
|
||||
|
@ -81,8 +80,8 @@ fun SpaceJoinRequestScreen(
|
|||
Text(
|
||||
text = stringResource(
|
||||
R.string.multiplayer_space_join_request_header,
|
||||
spaceJoinRequestView.memberName,
|
||||
spaceJoinRequestView.spaceName
|
||||
state.memberName,
|
||||
state.spaceName
|
||||
),
|
||||
style = HeadlineHeading,
|
||||
textAlign = TextAlign.Center,
|
||||
|
@ -91,36 +90,7 @@ fun SpaceJoinRequestScreen(
|
|||
),
|
||||
color = colorResource(id = R.color.text_primary)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(IntrinsicSize.Min)
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.background(
|
||||
color = colorResource(id = R.color.shape_tertiary),
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = spaceJoinRequestView.comment,
|
||||
style = BodyCalloutRegular,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(4.dp)
|
||||
.background(
|
||||
color = colorResource(id = R.color.glyph_active),
|
||||
shape = RoundedCornerShape(
|
||||
topStart = 4.dp,
|
||||
bottomStart = 4.dp
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
ButtonSecondary(
|
||||
text = stringResource(R.string.multiplayer_space_add_viewer),
|
||||
onClick = throttledClick(
|
||||
|
@ -156,3 +126,35 @@ fun SpaceJoinRequestScreen(
|
|||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CommentView() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(IntrinsicSize.Min)
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.background(
|
||||
color = colorResource(id = R.color.shape_tertiary),
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = "",
|
||||
style = BodyCalloutRegular,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(4.dp)
|
||||
.background(
|
||||
color = colorResource(id = R.color.glyph_active),
|
||||
shape = RoundedCornerShape(
|
||||
topStart = 4.dp,
|
||||
bottomStart = 4.dp
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@ fun ShareSpaceScreen(
|
|||
viewState: ShareSpaceViewModel.ViewState,
|
||||
onRegenerateInviteLinkClicked: () -> Unit,
|
||||
onShareInviteLinkClicked: () -> Unit,
|
||||
onRequestAction: (ShareSpaceMemberView.Config.Request) -> Unit
|
||||
onViewRequestClicked: (ShareSpaceMemberView) -> Unit,
|
||||
onApproveUnjoinRequestClicked: (ShareSpaceMemberView) -> Unit
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
|
@ -98,7 +99,12 @@ fun ShareSpaceScreen(
|
|||
SpaceMemberRequest(
|
||||
member = member.obj,
|
||||
request = config,
|
||||
onRequestAction = onRequestAction
|
||||
onViewRequestClicked = {
|
||||
onViewRequestClicked(member)
|
||||
},
|
||||
onApproveUnjoinRequestClicked = {
|
||||
onApproveUnjoinRequestClicked(member)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +192,8 @@ private fun SpaceMember(
|
|||
private fun SpaceMemberRequest(
|
||||
member: ObjectWrapper.Participant,
|
||||
request: ShareSpaceMemberView.Config.Request,
|
||||
onRequestAction: (ShareSpaceMemberView.Config.Request) -> Unit
|
||||
onViewRequestClicked: () -> Unit,
|
||||
onApproveUnjoinRequestClicked: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
@ -245,7 +252,7 @@ private fun SpaceMemberRequest(
|
|||
ButtonSecondary(
|
||||
text = stringResource(R.string.multiplayer_view_request),
|
||||
onClick = throttledClick(
|
||||
onClick = { onRequestAction(request) }
|
||||
onClick = { onViewRequestClicked() }
|
||||
),
|
||||
size = ButtonSize.Small,
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
|
@ -255,7 +262,7 @@ private fun SpaceMemberRequest(
|
|||
ButtonSecondary(
|
||||
text = stringResource(R.string.multiplayer_approve_request),
|
||||
onClick = throttledClick(
|
||||
onClick = { onRequestAction(request) }
|
||||
onClick = { onApproveUnjoinRequestClicked() }
|
||||
),
|
||||
size = ButtonSize.Small,
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
|
@ -278,7 +285,8 @@ fun SpaceJoinRequestPreview() {
|
|||
)
|
||||
),
|
||||
request = ShareSpaceMemberView.Config.Request.Join,
|
||||
onRequestAction = {},
|
||||
onApproveUnjoinRequestClicked = {},
|
||||
onViewRequestClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -294,7 +302,8 @@ fun SpaceUnjoinRequestPreview() {
|
|||
)
|
||||
),
|
||||
request = ShareSpaceMemberView.Config.Request.Unjoin,
|
||||
onRequestAction = {},
|
||||
onApproveUnjoinRequestClicked = {},
|
||||
onViewRequestClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -307,7 +316,6 @@ fun ShareSpaceScreenPreview() {
|
|||
),
|
||||
onShareInviteLinkClicked = {},
|
||||
onRegenerateInviteLinkClicked = {},
|
||||
onRequestAction = {},
|
||||
members = buildList {
|
||||
add(
|
||||
ShareSpaceMemberView(
|
||||
|
@ -352,7 +360,9 @@ fun ShareSpaceScreenPreview() {
|
|||
config = ShareSpaceMemberView.Config.Request.Join
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
onApproveUnjoinRequestClicked = {},
|
||||
onViewRequestClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,9 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId
|
|||
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 ApproveJoinSpaceRequest(
|
||||
class ApproveJoinSpaceRequest @Inject constructor(
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<ApproveJoinSpaceRequest.Params, Unit>(dispatchers.io) {
|
||||
|
|
|
@ -6,8 +6,9 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId
|
|||
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 DeclineSpaceJoinRequest(
|
||||
class DeclineSpaceJoinRequest @Inject constructor(
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<DeclineSpaceJoinRequest.Params, Unit>(dispatchers.io) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.anytypeio.anytype.presentation.multiplayer
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.multiplayer.ParticipantPermissions
|
||||
import com.anytypeio.anytype.core_models.multiplayer.ParticipantStatus
|
||||
|
@ -36,7 +37,7 @@ class ShareSpaceViewModel(
|
|||
viewModelScope.launch {
|
||||
container.subscribe(
|
||||
StoreSearchParams(
|
||||
subscription = this::class.java.toGenericString(),
|
||||
subscription = SHARE_SPACE_SUBSCRIPTION,
|
||||
filters = ObjectSearchConstants.filterParticipants(
|
||||
spaces = listOf(params.space.id)
|
||||
),
|
||||
|
@ -85,6 +86,28 @@ class ShareSpaceViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onViewRequestClicked(view: ShareSpaceMemberView) {
|
||||
viewModelScope.launch {
|
||||
commands.emit(
|
||||
Command.ViewJoinRequest(
|
||||
space = params.space,
|
||||
member = view.obj.id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onApproveUnjoinRequestClicked(view: ShareSpaceMemberView) {
|
||||
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
viewModelScope.launch {
|
||||
container.unsubscribe(subscriptions = listOf(SHARE_SPACE_SUBSCRIPTION))
|
||||
}
|
||||
super.onCleared()
|
||||
}
|
||||
|
||||
class Factory @Inject constructor(
|
||||
private val params: Params,
|
||||
private val generateSpaceInviteLink: GenerateSpaceInviteLink,
|
||||
|
@ -109,6 +132,11 @@ class ShareSpaceViewModel(
|
|||
|
||||
sealed class Command {
|
||||
data class ShareInviteLink(val link: String) : Command()
|
||||
data class ViewJoinRequest(val space: SpaceId, val member: Id) : Command()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SHARE_SPACE_SUBSCRIPTION = "share-space-subscription"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,10 +197,4 @@ data class ShareSpaceMemberView(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class SpaceJoinRequestView(
|
||||
val memberName: String,
|
||||
val spaceName: String,
|
||||
val comment: String
|
||||
)
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
package com.anytypeio.anytype.presentation.multiplayer
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.core_models.DVFilter
|
||||
import com.anytypeio.anytype.core_models.DVFilterCondition
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.multiplayer.ParticipantPermissions
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_utils.ext.msg
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.multiplayer.ApproveJoinSpaceRequest
|
||||
import com.anytypeio.anytype.domain.multiplayer.DeclineSpaceJoinRequest
|
||||
import com.anytypeio.anytype.domain.search.SearchObjects
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
import com.anytypeio.anytype.presentation.common.ViewState
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
class SpaceJoinRequestViewModel(
|
||||
private val params: Params,
|
||||
private val approveJoinSpaceRequest: ApproveJoinSpaceRequest,
|
||||
private val declineSpaceJoinRequest: DeclineSpaceJoinRequest,
|
||||
private val searchObjects: SearchObjects,
|
||||
private val spaceManager: SpaceManager
|
||||
): BaseViewModel() {
|
||||
|
||||
val isDismissed = MutableStateFlow(false)
|
||||
|
||||
private val state = MutableStateFlow<State>(State.Init)
|
||||
|
||||
val viewState = MutableStateFlow<ViewState>(ViewState.Init)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
val config = spaceManager.getConfig()
|
||||
if (config != null && config.space == params.space.id) {
|
||||
searchObjects(
|
||||
SearchObjects.Params(
|
||||
sorts = emptyList(),
|
||||
filters = buildList {
|
||||
add(
|
||||
DVFilter(
|
||||
relation = Relations.IS_ARCHIVED,
|
||||
condition = DVFilterCondition.NOT_EQUAL,
|
||||
value = true
|
||||
)
|
||||
)
|
||||
add(
|
||||
DVFilter(
|
||||
relation = Relations.IS_DELETED,
|
||||
condition = DVFilterCondition.NOT_EQUAL,
|
||||
value = true
|
||||
)
|
||||
)
|
||||
add(
|
||||
DVFilter(
|
||||
relation = Relations.ID,
|
||||
condition = DVFilterCondition.IN,
|
||||
value = listOf(config.spaceView, params.member)
|
||||
)
|
||||
)
|
||||
},
|
||||
limit = 2,
|
||||
keys = listOf(
|
||||
Relations.ID,
|
||||
Relations.SPACE_ID,
|
||||
Relations.TARGET_SPACE_ID,
|
||||
Relations.IDENTITY,
|
||||
Relations.ICON_IMAGE,
|
||||
Relations.NAME
|
||||
)
|
||||
)
|
||||
).process(
|
||||
failure = { e ->
|
||||
Timber.e(e, "Error while fetching space data and member data").also {
|
||||
sendToast(e.msg())
|
||||
}
|
||||
},
|
||||
success = { wrappers ->
|
||||
val spaceView = wrappers.firstOrNull { it.id == config.spaceView }
|
||||
val member = wrappers.firstOrNull { it.id == params.member }
|
||||
if (spaceView != null && member != null) {
|
||||
state.value = State.Success(
|
||||
member = ObjectWrapper.Participant(member.map),
|
||||
spaceView = ObjectWrapper.SpaceView(spaceView.map)
|
||||
)
|
||||
} else {
|
||||
state.value = State.Error
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
state.value = State.Error
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
state.collect { curr ->
|
||||
viewState.value = when (curr) {
|
||||
is State.Error -> ViewState.Error
|
||||
is State.Init -> ViewState.Init
|
||||
is State.Success -> ViewState.Success(
|
||||
memberName = curr.member.name.orEmpty(),
|
||||
spaceName = curr.spaceView.name.orEmpty()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onRejectRequestClicked() {
|
||||
viewModelScope.launch {
|
||||
when(val curr = state.value) {
|
||||
is State.Error -> {
|
||||
// TODO send toast
|
||||
}
|
||||
is State.Init -> {
|
||||
// Do nothing
|
||||
}
|
||||
is State.Success -> {
|
||||
declineSpaceJoinRequest.async(
|
||||
DeclineSpaceJoinRequest.Params(
|
||||
space = params.space,
|
||||
identity = curr.member.identity
|
||||
)
|
||||
).fold(
|
||||
onSuccess = {
|
||||
isDismissed.value = true
|
||||
},
|
||||
onFailure = { e ->
|
||||
Timber.e(e, "Error while approving join-space request").also {
|
||||
sendToast(e.msg())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onJoinAsReaderClicked() {
|
||||
viewModelScope.launch {
|
||||
when(val curr = state.value) {
|
||||
is State.Error -> {
|
||||
// TODO send toast
|
||||
}
|
||||
is State.Init -> {
|
||||
// Do nothing
|
||||
}
|
||||
is State.Success -> {
|
||||
approveJoinSpaceRequest.async(
|
||||
ApproveJoinSpaceRequest.Params(
|
||||
space = params.space,
|
||||
identity = curr.member.identity,
|
||||
permissions = ParticipantPermissions.READER
|
||||
)
|
||||
).fold(
|
||||
onSuccess = {
|
||||
isDismissed.value = true
|
||||
},
|
||||
onFailure = { e ->
|
||||
Timber.e(e, "Error while approving join-space request").also {
|
||||
sendToast(e.msg())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onJoinAsEditorClicked() {
|
||||
viewModelScope.launch {
|
||||
when(val curr = state.value) {
|
||||
is State.Error -> {
|
||||
// TODO send toast
|
||||
}
|
||||
is State.Init -> {
|
||||
// Do nothing
|
||||
}
|
||||
is State.Success -> {
|
||||
approveJoinSpaceRequest.async(
|
||||
ApproveJoinSpaceRequest.Params(
|
||||
space = params.space,
|
||||
identity = curr.member.identity,
|
||||
permissions = ParticipantPermissions.WRITER
|
||||
)
|
||||
).fold(
|
||||
onSuccess = {
|
||||
isDismissed.value = true
|
||||
},
|
||||
onFailure = { e ->
|
||||
Timber.e(e, "Error while approving join-space request").also {
|
||||
sendToast(e.msg())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Factory @Inject constructor(
|
||||
private val params: Params,
|
||||
private val approveJoinSpaceRequest: ApproveJoinSpaceRequest,
|
||||
private val declineSpaceJoinRequest: DeclineSpaceJoinRequest,
|
||||
private val searchObjects: SearchObjects,
|
||||
private val spaceManager: SpaceManager
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = SpaceJoinRequestViewModel(
|
||||
params = params,
|
||||
declineSpaceJoinRequest = declineSpaceJoinRequest,
|
||||
approveJoinSpaceRequest = approveJoinSpaceRequest,
|
||||
searchObjects = searchObjects,
|
||||
spaceManager = spaceManager
|
||||
) as T
|
||||
}
|
||||
|
||||
data class Params(val space: SpaceId, val member: Id)
|
||||
|
||||
sealed class State {
|
||||
object Init : State()
|
||||
data class Success(
|
||||
val member: ObjectWrapper.Participant,
|
||||
val spaceView: ObjectWrapper.SpaceView
|
||||
) : State()
|
||||
object Error : State()
|
||||
}
|
||||
|
||||
sealed class ViewState {
|
||||
object Init: ViewState()
|
||||
data class Success(val memberName: String, val spaceName: String): ViewState()
|
||||
object Error: ViewState()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue