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

DROID-2319 Multiplayer | Enhancement | Space settings behavior for read-only spaces (#1007)

This commit is contained in:
Evgenii Kozlov 2024-03-15 00:36:59 +01:00 committed by GitHub
parent 6096a11368
commit c0ee5ef7eb
Signed by: github
GPG key ID: B5690EEEBB952194
6 changed files with 46 additions and 81 deletions

View file

@ -15,6 +15,7 @@ import com.anytypeio.anytype.domain.debugging.DebugSpaceContentSaver
import com.anytypeio.anytype.domain.debugging.DebugSpaceShareDownloader
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.spaces.SpaceGradientProvider
import com.anytypeio.anytype.presentation.spaces.SpaceSettingsViewModel
@ -97,4 +98,5 @@ interface SpaceSettingsDependencies : ComponentDependencies {
fun container(): StorelessSubscriptionContainer
fun config(): ConfigStorage
fun context(): Context
fun userPermission(): UserPermissionProvider
}

View file

@ -152,7 +152,7 @@ fun HomeScreen(
}
}
AnimatedVisibility(
visible = mode is InteractionMode.Default,
visible = mode !is InteractionMode.Edit,
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 20.dp),
@ -165,7 +165,8 @@ fun HomeScreen(
onCreateNewObjectClicked = throttledClick(onCreateNewObjectClicked),
onProfileClicked = throttledClick(onProfileClicked),
onCreateNewObjectLongClicked = onCreateNewObjectLongClicked,
modifier = Modifier
modifier = Modifier,
isReadOnlyAccess = mode is InteractionMode.ReadOnly
)
}
}
@ -526,7 +527,6 @@ fun HomeScreenButton(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun HomeScreenBottomToolbar(
profileIcon: ProfileIconView,
@ -534,7 +534,8 @@ fun HomeScreenBottomToolbar(
onSearchClicked: () -> Unit,
onCreateNewObjectClicked: () -> Unit,
onCreateNewObjectLongClicked: () -> Unit,
onProfileClicked: () -> Unit
onProfileClicked: () -> Unit,
isReadOnlyAccess: Boolean
) {
val haptic = LocalHapticFeedback.current
Row(
@ -561,16 +562,22 @@ fun HomeScreenBottomToolbar(
Box(
modifier = Modifier
.weight(1f)
.alpha(if (isReadOnlyAccess) 0.2f else 1f)
.fillMaxSize()
.noRippleCombinedClickable(
onLongClicked = {
onCreateNewObjectLongClicked().also {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}
},
onClick = {
onCreateNewObjectClicked()
}
.then(
if (isReadOnlyAccess)
Modifier.noRippleCombinedClickable(
onLongClicked = {
onCreateNewObjectLongClicked().also {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}
},
onClick = {
onCreateNewObjectClicked()
}
)
else
Modifier
)
) {
Image(

View file

@ -8,7 +8,6 @@ import com.anytypeio.anytype.analytics.base.EventsDictionary
import com.anytypeio.anytype.analytics.base.EventsPropertiesKey
import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.analytics.props.Props
import com.anytypeio.anytype.core_models.Account
import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.Filepath
@ -23,23 +22,21 @@ 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.GetAccount
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.library.StoreSearchParams
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.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.search.ObjectSearchConstants
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.flow.mapNotNull
import kotlinx.coroutines.launch
import timber.log.Timber
@ -56,7 +53,7 @@ class SpaceSettingsViewModel(
private val configStorage: ConfigStorage,
private val debugSpaceShareDownloader: DebugSpaceShareDownloader,
private val spaceGradientProvider: SpaceGradientProvider,
private val getAccount: GetAccount
private val userPermissionProvider: UserPermissionProvider
): BaseViewModel() {
val commands = MutableSharedFlow<Command>()
@ -73,7 +70,6 @@ class SpaceSettingsViewModel(
eventName = EventsDictionary.screenSettingSpacesSpaceIndex
)
}
proceedWithUserAsSpaceMemberPermissions()
proceedWithFetchingSpaceMetaData()
}
@ -117,7 +113,7 @@ class SpaceSettingsViewModel(
)
).mapNotNull { results ->
results.firstOrNull()
}.combine(permissions) { wrapper, permission ->
}.combine(userPermissionProvider.observe(params.space)) { wrapper, permission ->
val spaceView = ObjectWrapper.SpaceView(wrapper.map)
SpaceData(
name = wrapper.name.orEmpty(),
@ -135,7 +131,7 @@ class SpaceSettingsViewModel(
network = config?.network.orEmpty(),
isDeletable = resolveIsSpaceDeletable(spaceView),
spaceType = spaceView.spaceAccessType?.asSpaceType() ?: UNKNOWN_SPACE_TYPE,
permissions = permission
permissions = permission ?: SpaceMemberPermissions.NO_PERMISSIONS
)
}.collect { spaceData ->
spaceViewState.value = ViewState.Success(spaceData)
@ -146,55 +142,6 @@ class SpaceSettingsViewModel(
private fun resolveIsSpaceDeletable(spaceView: ObjectWrapper.SpaceView) =
spaceView.spaceAccessType != null && spaceView.spaceAccessType != SpaceAccessType.PERSONAL
private fun proceedWithUserAsSpaceMemberPermissions() {
viewModelScope.launch {
getAccount.async(Unit).fold(
onSuccess = { account ->
proceedWithSpaceMemberPermissionSubscription(account)
},
onFailure = {
Timber.e(it, "Could not get account")
}
)
}
}
private suspend fun proceedWithSpaceMemberPermissionSubscription(account: Account) {
storelessSubscriptionContainer.subscribe(
searchParams = StoreSearchParams(
subscription = SPACE_SETTINGS_PARTICIPANT_SUBSCRIPTION,
filters = buildList {
addAll(
ObjectSearchConstants.filterParticipants(
spaces = listOf(params.space.id)
)
)
add(
DVFilter(
relation = Relations.IDENTITY,
value = account.id,
condition = DVFilterCondition.EQUAL
)
)
},
sorts = emptyList(),
keys = ObjectSearchConstants.spaceMemberKeys,
limit = 1
)
).map { results ->
if (results.isNotEmpty())
ObjectWrapper.SpaceMember(results.first().map)
else
null
}.collect { user ->
if (user != null)
permissions.value =
user.permissions ?: SpaceMemberPermissions.NO_PERMISSIONS
else
Timber.w("User-as-space-member permission is not found.")
}
}
fun onNameSet(name: String) {
Timber.d("onNameSet")
if (name.isEmpty()) return
@ -366,7 +313,6 @@ class SpaceSettingsViewModel(
class Factory @Inject constructor(
private val params: Params,
private val getAccount: GetAccount,
private val analytics: Analytics,
private val storelessSubscriptionContainer: StorelessSubscriptionContainer,
private val urlBuilder: UrlBuilder,
@ -376,7 +322,8 @@ class SpaceSettingsViewModel(
private val deleteSpace: DeleteSpace,
private val configStorage: ConfigStorage,
private val debugFileShareDownloader: DebugSpaceShareDownloader,
private val spaceGradientProvider: SpaceGradientProvider
private val spaceGradientProvider: SpaceGradientProvider,
private val userPermissionProvider: UserPermissionProvider
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
@ -393,7 +340,7 @@ class SpaceSettingsViewModel(
debugSpaceShareDownloader = debugFileShareDownloader,
spaceGradientProvider = spaceGradientProvider,
params = params,
getAccount = getAccount
userPermissionProvider = userPermissionProvider
) as T
}
@ -402,6 +349,5 @@ class SpaceSettingsViewModel(
companion object {
const val SPACE_DEBUG_MSG = "Kindly share this debug logs with Anytype developers."
const val SPACE_SETTINGS_SUBSCRIPTION = "subscription.space-settings.space-views"
const val SPACE_SETTINGS_PARTICIPANT_SUBSCRIPTION = "subscription.space-settings.participant"
}
}

View file

@ -32,7 +32,8 @@ fun SpaceHeader(
icon: SpaceIconView?,
modifier: Modifier = Modifier,
onNameSet: (String) -> Unit,
onRandomGradientClicked: () -> Unit
onRandomGradientClicked: () -> Unit,
isEditEnabled: Boolean
) {
val isSpaceIconMenuExpanded = remember {
mutableStateOf(false)
@ -78,7 +79,8 @@ fun SpaceHeader(
SpaceNameBlock(
modifier = Modifier,
name = name,
onNameSet = onNameSet
onNameSet = onNameSet,
isEditEnabled = isEditEnabled
)
}
}

View file

@ -67,7 +67,8 @@ fun Section(modifier: Modifier = Modifier, title: String) {
fun SpaceNameBlock(
modifier: Modifier = Modifier,
name: String,
onNameSet: (String) -> Unit
onNameSet: (String) -> Unit,
isEditEnabled: Boolean
) {
val nameValue = remember { mutableStateOf(name) }
@ -99,6 +100,7 @@ fun SpaceNameBlock(
focusManager.clearFocus()
}
),
isEditEnabled = isEditEnabled
)
}
}
@ -199,22 +201,22 @@ fun SpaceImageBlock(
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SettingsTextField(
value: String,
onValueChange: (String) -> Unit,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardActions: KeyboardActions = KeyboardActions.Default,
isEditEnabled: Boolean
) {
@OptIn(ExperimentalMaterialApi::class)
BasicTextField(
value = value,
modifier = Modifier
.padding(top = 4.dp, end = 20.dp)
.fillMaxWidth(),
onValueChange = onValueChange,
enabled = true,
enabled = isEditEnabled,
readOnly = false,
textStyle = HeadlineHeading.copy(color = colorResource(id = R.color.text_primary)),
cursorBrush = SolidColor(colorResource(id = R.color.orange)),

View file

@ -82,7 +82,13 @@ fun SpaceSettingsScreen(
else -> null
},
onNameSet = onNameSet,
onRandomGradientClicked = onRandomGradientClicked
onRandomGradientClicked = onRandomGradientClicked,
isEditEnabled = when(spaceData) {
is ViewState.Error -> false
ViewState.Init -> false
ViewState.Loading -> false
is ViewState.Success -> spaceData.data.permissions.isOwnerOrEditor()
}
)
}
item { Divider() }