mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2250 Multiplayer | Fix | Show invite link and join/leave requrests only to space owner (#1104)
This commit is contained in:
parent
9a0432ef45
commit
26e632059f
6 changed files with 121 additions and 80 deletions
|
@ -10,6 +10,7 @@ import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
|||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
import com.anytypeio.anytype.presentation.multiplayer.ShareSpaceViewModel
|
||||
import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment
|
||||
|
@ -56,4 +57,5 @@ interface ShareSpaceDependencies : ComponentDependencies {
|
|||
fun dispatchers(): AppCoroutineDispatchers
|
||||
fun container(): StorelessSubscriptionContainer
|
||||
fun config(): ConfigStorage
|
||||
fun permissions(): UserPermissionProvider
|
||||
}
|
|
@ -102,7 +102,11 @@ fun ShareSpaceScreen(
|
|||
item {
|
||||
var isMenuExpanded by remember { mutableStateOf(false) }
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
Toolbar(title = stringResource(R.string.multiplayer_share_space))
|
||||
if (isCurrentUserOwner) {
|
||||
Toolbar(title = stringResource(R.string.multiplayer_sharing))
|
||||
} else {
|
||||
Toolbar(title = stringResource(R.string.multiplayer_members))
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
|
@ -162,10 +166,12 @@ fun ShareSpaceScreen(
|
|||
}
|
||||
}
|
||||
}
|
||||
item {
|
||||
Section(
|
||||
title = stringResource(R.string.multiplayer_members_and_requests)
|
||||
)
|
||||
if (isCurrentUserOwner) {
|
||||
item {
|
||||
Section(
|
||||
title = stringResource(R.string.multiplayer_members_and_requests)
|
||||
)
|
||||
}
|
||||
}
|
||||
members.forEachIndexed { index, member ->
|
||||
item {
|
||||
|
@ -450,13 +456,13 @@ private fun SpaceMemberRequest(
|
|||
Spacer(modifier = Modifier.height(2.dp))
|
||||
val color = when(request) {
|
||||
ShareSpaceMemberView.Config.Request.Join -> ThemeColor.PINK
|
||||
ShareSpaceMemberView.Config.Request.Unjoin -> ThemeColor.RED
|
||||
ShareSpaceMemberView.Config.Request.Leave -> ThemeColor.RED
|
||||
}
|
||||
val text = when(request) {
|
||||
ShareSpaceMemberView.Config.Request.Join -> stringResource(
|
||||
id = R.string.multiplayer_joining_requested
|
||||
)
|
||||
ShareSpaceMemberView.Config.Request.Unjoin -> stringResource(
|
||||
ShareSpaceMemberView.Config.Request.Leave -> stringResource(
|
||||
id = R.string.multiplayer_unjoining_requested
|
||||
)
|
||||
}
|
||||
|
@ -486,7 +492,7 @@ private fun SpaceMemberRequest(
|
|||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
ShareSpaceMemberView.Config.Request.Unjoin -> {
|
||||
ShareSpaceMemberView.Config.Request.Leave -> {
|
||||
ButtonSecondary(
|
||||
text = stringResource(R.string.multiplayer_approve_request),
|
||||
onClick = throttledClick(
|
||||
|
@ -531,7 +537,7 @@ fun SpaceUnjoinRequestPreview() {
|
|||
)
|
||||
),
|
||||
icon = SpaceMemberIconView.Placeholder(name = "Konstantin"),
|
||||
request = ShareSpaceMemberView.Config.Request.Unjoin,
|
||||
request = ShareSpaceMemberView.Config.Request.Leave,
|
||||
onApproveUnjoinRequestClicked = {},
|
||||
onViewRequestClicked = {}
|
||||
)
|
||||
|
@ -581,7 +587,7 @@ fun ShareSpaceScreenPreview() {
|
|||
Relations.NAME to "Aleksey"
|
||||
)
|
||||
),
|
||||
config = ShareSpaceMemberView.Config.Request.Unjoin,
|
||||
config = ShareSpaceMemberView.Config.Request.Leave,
|
||||
icon = SpaceMemberIconView.Placeholder(
|
||||
name = "Aleksey"
|
||||
)
|
||||
|
|
|
@ -1316,6 +1316,7 @@
|
|||
<string name="multiplayer_tap_to_write_request_to_join_comment">Tap to write your comment</string>
|
||||
<string name="multiplayer_share_space">Share space</string>
|
||||
<string name="multiplayer_members_and_requests">Members and requests</string>
|
||||
<string name="multiplayer_members">Members</string>
|
||||
<string name="multiplayer_unjoining_requested">Unjoining requested</string>
|
||||
<string name="multiplayer_joining_requested">Joining requested</string>
|
||||
<string name="multiplayer_approve_request">Approve</string>
|
||||
|
|
|
@ -282,7 +282,9 @@ class HomeScreenViewModel(
|
|||
.async(params = previouslyOpenedWidgetObject)
|
||||
.fold(
|
||||
onSuccess = { closed.add(previouslyOpenedWidgetObject) },
|
||||
onFailure = { Timber.e(it, "Error while closing object from history") }
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while closing object from history: $previouslyOpenedWidgetObject")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.anytypeio.anytype.domain.multiplayer.GetSpaceInviteLink
|
|||
import com.anytypeio.anytype.domain.multiplayer.RemoveSpaceMembers
|
||||
import com.anytypeio.anytype.domain.multiplayer.RevokeSpaceInviteLink
|
||||
import com.anytypeio.anytype.domain.multiplayer.StopSharingSpace
|
||||
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
|
||||
import com.anytypeio.anytype.domain.`object`.canChangeReaderToWriter
|
||||
import com.anytypeio.anytype.domain.`object`.canChangeWriterToReader
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
|
@ -47,8 +48,9 @@ class ShareSpaceViewModel(
|
|||
private val changeSpaceMemberPermissions: ChangeSpaceMemberPermissions,
|
||||
private val stopSharingSpace: StopSharingSpace,
|
||||
private val container: StorelessSubscriptionContainer,
|
||||
private val permissions: UserPermissionProvider,
|
||||
private val getAccount: GetAccount,
|
||||
private val urlBuilder: UrlBuilder
|
||||
private val urlBuilder: UrlBuilder,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val members = MutableStateFlow<List<ShareSpaceMemberView>>(emptyList())
|
||||
|
@ -62,7 +64,19 @@ class ShareSpaceViewModel(
|
|||
|
||||
init {
|
||||
Timber.d("Share-space init with params: $params")
|
||||
proceedWithUserPermissions()
|
||||
proceedWithSubscriptions()
|
||||
|
||||
}
|
||||
|
||||
private fun proceedWithUserPermissions() {
|
||||
viewModelScope.launch {
|
||||
permissions
|
||||
.observe(space = params.space)
|
||||
.collect { permission ->
|
||||
isCurrentUserOwner.value = permission == OWNER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithSubscriptions() {
|
||||
|
@ -78,8 +92,8 @@ class ShareSpaceViewModel(
|
|||
combine(
|
||||
container.subscribe(spaceSearchParams),
|
||||
container.subscribe(spaceMembersSearchParams),
|
||||
getAccount.asFlow(Unit)
|
||||
) { spaceResponse, membersResponse, accountId ->
|
||||
isCurrentUserOwner
|
||||
) { spaceResponse, membersResponse, isCurrentUserOwner ->
|
||||
|
||||
val spaceView = spaceResponse.firstOrNull()?.let { ObjectWrapper.SpaceView(it.map) }
|
||||
val spaceMembers = membersResponse.map { ObjectWrapper.SpaceMember(it.map) }
|
||||
|
@ -92,48 +106,45 @@ class ShareSpaceViewModel(
|
|||
obj = m,
|
||||
urlBuilder = urlBuilder,
|
||||
canChangeWriterToReader = canChangeWriterToReader,
|
||||
canChangeReaderToWriter = canChangeReaderToWriter
|
||||
canChangeReaderToWriter = canChangeReaderToWriter,
|
||||
includeRequests = isCurrentUserOwner
|
||||
)
|
||||
}
|
||||
|
||||
Triple(spaceView, spaceViewMembers, accountId)
|
||||
Triple(spaceView, spaceViewMembers, isCurrentUserOwner)
|
||||
}.catch {
|
||||
Timber.e(
|
||||
it, "Error while $SHARE_SPACE_MEMBER_SUBSCRIPTION " +
|
||||
"and $SHARE_SPACE_SPACE_SUBSCRIPTION subscription"
|
||||
)
|
||||
}.collect { (spaceView, spaceViewMembers, accountId) ->
|
||||
}.collect { (spaceView, spaceViewMembers, isCurrentUserOwner) ->
|
||||
spaceAccessType.value = spaceView?.spaceAccessType
|
||||
setShareLinkViewState(spaceView)
|
||||
proceedWithIsCurrentUserOwner(spaceViewMembers, accountId.id)
|
||||
setShareLinkViewState(spaceView, isCurrentUserOwner)
|
||||
members.value = spaceViewMembers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithIsCurrentUserOwner(
|
||||
members: List<ShareSpaceMemberView>,
|
||||
account: Id
|
||||
private suspend fun setShareLinkViewState(
|
||||
space: ObjectWrapper.SpaceView?,
|
||||
isCurrentUserOwner: Boolean
|
||||
) {
|
||||
isCurrentUserOwner.value = members.any { member ->
|
||||
with(member.obj) {
|
||||
identity.isNotEmpty() && identity == account && permissions == OWNER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun setShareLinkViewState(space: ObjectWrapper.SpaceView?) {
|
||||
shareLinkViewState.value = when (space?.spaceAccessType) {
|
||||
SpaceAccessType.PRIVATE -> ShareLinkViewState.NotGenerated
|
||||
SpaceAccessType.SHARED -> {
|
||||
val link = getSpaceInviteLink.async(params.space)
|
||||
if (link.isSuccess) {
|
||||
ShareLinkViewState.Shared(link.getOrThrow().scheme)
|
||||
} else {
|
||||
ShareLinkViewState.NotGenerated
|
||||
if (isCurrentUserOwner) {
|
||||
shareLinkViewState.value = when (space?.spaceAccessType) {
|
||||
SpaceAccessType.PRIVATE -> ShareLinkViewState.NotGenerated
|
||||
SpaceAccessType.SHARED -> {
|
||||
val link = getSpaceInviteLink.async(params.space)
|
||||
if (link.isSuccess) {
|
||||
ShareLinkViewState.Shared(link.getOrThrow().scheme)
|
||||
} else {
|
||||
ShareLinkViewState.NotGenerated
|
||||
}
|
||||
}
|
||||
|
||||
else -> ShareLinkViewState.Init
|
||||
}
|
||||
else -> ShareLinkViewState.Init
|
||||
} else {
|
||||
ShareLinkViewState.Init
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,7 +412,8 @@ class ShareSpaceViewModel(
|
|||
private val approveLeaveSpaceRequest: ApproveLeaveSpaceRequest,
|
||||
private val container: StorelessSubscriptionContainer,
|
||||
private val urlBuilder: UrlBuilder,
|
||||
private val getSpaceInviteLink: GetSpaceInviteLink
|
||||
private val getSpaceInviteLink: GetSpaceInviteLink,
|
||||
private val permissions: UserPermissionProvider
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = ShareSpaceViewModel(
|
||||
|
@ -415,7 +427,8 @@ class ShareSpaceViewModel(
|
|||
urlBuilder = urlBuilder,
|
||||
getAccount = getAccount,
|
||||
getSpaceInviteLink = getSpaceInviteLink,
|
||||
approveLeaveSpaceRequest = approveLeaveSpaceRequest
|
||||
approveLeaveSpaceRequest = approveLeaveSpaceRequest,
|
||||
permissions = permissions
|
||||
) as T
|
||||
}
|
||||
|
||||
|
@ -455,15 +468,15 @@ data class ShareSpaceMemberView(
|
|||
) {
|
||||
sealed class Config {
|
||||
sealed class Request : Config() {
|
||||
object Join: Request()
|
||||
object Unjoin: Request()
|
||||
data object Join: Request()
|
||||
data object Leave: Request()
|
||||
}
|
||||
sealed class Member: Config() {
|
||||
object Owner: Member()
|
||||
object Writer: Member()
|
||||
object Reader: Member()
|
||||
object NoPermissions: Member()
|
||||
object Unknown: Member()
|
||||
data object Owner: Member()
|
||||
data object Writer: Member()
|
||||
data object Reader: Member()
|
||||
data object NoPermissions: Member()
|
||||
data object Unknown: Member()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,7 +485,8 @@ data class ShareSpaceMemberView(
|
|||
obj: ObjectWrapper.SpaceMember,
|
||||
urlBuilder: UrlBuilder,
|
||||
canChangeWriterToReader: Boolean,
|
||||
canChangeReaderToWriter: Boolean
|
||||
canChangeReaderToWriter: Boolean,
|
||||
includeRequests: Boolean
|
||||
) : ShareSpaceMemberView? {
|
||||
val icon = SpaceMemberIconView.icon(
|
||||
obj = obj,
|
||||
|
@ -512,16 +526,26 @@ data class ShareSpaceMemberView(
|
|||
)
|
||||
}
|
||||
}
|
||||
ParticipantStatus.JOINING -> ShareSpaceMemberView(
|
||||
obj = obj,
|
||||
config = Config.Request.Join,
|
||||
icon = icon
|
||||
)
|
||||
ParticipantStatus.REMOVING -> ShareSpaceMemberView(
|
||||
obj = obj,
|
||||
config = Config.Request.Unjoin,
|
||||
icon = icon
|
||||
)
|
||||
ParticipantStatus.JOINING -> {
|
||||
if (includeRequests)
|
||||
ShareSpaceMemberView(
|
||||
obj = obj,
|
||||
config = Config.Request.Join,
|
||||
icon = icon
|
||||
)
|
||||
else
|
||||
null
|
||||
}
|
||||
ParticipantStatus.REMOVING -> {
|
||||
if (includeRequests)
|
||||
ShareSpaceMemberView(
|
||||
obj = obj,
|
||||
config = Config.Request.Leave,
|
||||
icon = icon
|
||||
)
|
||||
else
|
||||
null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.DEFAULT_SPACE_TYPE
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.PRIVATE_SPACE_TYPE
|
||||
import com.anytypeio.anytype.core_models.SHARED_SPACE_TYPE
|
||||
import com.anytypeio.anytype.core_models.SpaceType
|
||||
|
@ -116,7 +116,8 @@ fun SpaceSettingsScreen(
|
|||
}
|
||||
SHARED_SPACE_TYPE -> {
|
||||
SharedSpaceSharing(
|
||||
onManageSharedSpaceClicked = onManageSharedSpaceClicked
|
||||
onManageSharedSpaceClicked = onManageSharedSpaceClicked,
|
||||
isUserOwner = state.data.permissions == SpaceMemberPermissions.OWNER
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -391,7 +392,8 @@ fun PrivateSpaceSharing(
|
|||
|
||||
@Composable
|
||||
fun SharedSpaceSharing(
|
||||
onManageSharedSpaceClicked: () -> Unit
|
||||
onManageSharedSpaceClicked: () -> Unit,
|
||||
isUserOwner: Boolean
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -417,7 +419,10 @@ fun SharedSpaceSharing(
|
|||
) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
text = stringResource(id = R.string.multiplayer_manage),
|
||||
text = if (isUserOwner)
|
||||
stringResource(id = R.string.multiplayer_manage)
|
||||
else
|
||||
stringResource(id = R.string.multiplayer_members),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = BodyRegular
|
||||
)
|
||||
|
@ -433,22 +438,6 @@ fun SharedSpaceSharing(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PrivateSpaceSharingPreview() {
|
||||
PrivateSpaceSharing(
|
||||
onSharePrivateSpaceClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SharedSpaceSharingPreview() {
|
||||
SharedSpaceSharing(
|
||||
onManageSharedSpaceClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TypeOfSpace(spaceType: SpaceType?) {
|
||||
Box(
|
||||
|
@ -480,4 +469,21 @@ fun TypeOfSpace(spaceType: SpaceType?) {
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PrivateSpaceSharingPreview() {
|
||||
PrivateSpaceSharing(
|
||||
onSharePrivateSpaceClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun SharedSpaceSharingPreview() {
|
||||
SharedSpaceSharing(
|
||||
onManageSharedSpaceClicked = {},
|
||||
isUserOwner = true
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue