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

DROID-3279 Navigation | Fix | Nav panel fixes (#2032)

This commit is contained in:
Evgenii Kozlov 2025-01-25 13:38:44 +01:00 committed by GitHub
parent 151e0a415e
commit 2cff1f68fe
Signed by: github
GPG key ID: B5690EEEBB952194
17 changed files with 341 additions and 137 deletions

View file

@ -851,13 +851,9 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
// TODO
}.launchIn(lifecycleScope)
vm.permission.onEach { permission ->
vm.navPanelState.onEach {
if (hasBinding) {
if (permission?.isOwnerOrEditor() == true) {
binding.bottomToolbar.setIsReadOnly(false)
} else {
binding.bottomToolbar.setIsReadOnly(true)
}
binding.bottomToolbar.setState(it)
}
}.launchIn(lifecycleScope)

View file

@ -46,6 +46,7 @@ import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationMenu
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.views.UXBody
import com.anytypeio.anytype.presentation.home.InteractionMode
import com.anytypeio.anytype.presentation.navigation.NavPanelState
import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction
import com.anytypeio.anytype.presentation.widgets.FromIndex
import com.anytypeio.anytype.presentation.widgets.ToIndex
@ -72,6 +73,7 @@ import org.burnoutcrew.reorderable.reorderable
@Composable
fun HomeScreen(
navPanelState: NavPanelState,
modifier: Modifier,
mode: InteractionMode,
widgets: List<WidgetView>,
@ -88,7 +90,6 @@ fun HomeScreen(
onSearchClicked: () -> Unit,
onCreateNewObjectClicked: () -> Unit,
onCreateNewObjectLongClicked: () -> Unit,
onBackClicked: () -> Unit,
onShareButtonClicked: () -> Unit,
onObjectCheckboxClicked: (Id, Boolean) -> Unit,
onSpaceWidgetClicked: () -> Unit,
@ -96,8 +97,7 @@ fun HomeScreen(
onSpaceShareIconClicked: (ObjectWrapper.SpaceView) -> Unit,
onSeeAllObjectsClicked: (WidgetView.Gallery) -> Unit,
onCreateObjectInsideWidget: (Id) -> Unit,
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit,
onBackLongClicked: () -> Unit
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit
) {
Box(modifier = modifier.fillMaxSize()) {
@ -156,13 +156,11 @@ fun HomeScreen(
exit = fadeOut() + slideOutVertically { it }
) {
BottomNavigationMenu(
state = navPanelState,
modifier = Modifier,
backClick = onBackClicked,
backLongClick = onBackLongClicked,
searchClick = onSearchClicked,
addDocClick = onCreateNewObjectClicked,
addDocLongClick = onCreateNewObjectLongClicked,
isOwnerOrEditor = mode !is InteractionMode.ReadOnly,
onShareButtonClicked = onShareButtonClicked
)
}

View file

@ -57,9 +57,6 @@ import com.anytypeio.anytype.ui.objects.types.pickers.ObjectTypeSelectionListene
import com.anytypeio.anytype.ui.objects.types.pickers.WidgetObjectTypeListener
import com.anytypeio.anytype.ui.objects.types.pickers.WidgetSourceTypeListener
import com.anytypeio.anytype.ui.payments.MembershipFragment
import com.anytypeio.anytype.ui.profile.ParticipantFragment
import com.anytypeio.anytype.ui.search.GlobalSearchScreen
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
import com.anytypeio.anytype.ui.settings.space.SpaceSettingsFragment
import com.anytypeio.anytype.ui.settings.typography
import com.anytypeio.anytype.ui.widgets.SelectWidgetSourceFragment
@ -179,9 +176,6 @@ class HomeScreenFragment : BaseComposeFragment(),
onCreateNewObjectLongClicked = throttledClick(
onClick = { vm.onCreateNewObjectLongClicked() }
),
onBackClicked = throttledClick(
onClick = { vm.onBackClicked(isSpaceRootScreen()) }
),
onSpaceWidgetClicked = throttledClick(
onClick = vm::onSpaceSettingsClicked
),
@ -192,8 +186,8 @@ class HomeScreenFragment : BaseComposeFragment(),
onSeeAllObjectsClicked = vm::onSeeAllObjectsClicked,
onCreateObjectInsideWidget = vm::onCreateObjectInsideWidget,
onCreateDataViewObject = vm::onCreateDataViewObject,
onBackLongClicked = vm::onBackLongClicked,
onShareButtonClicked = vm::onSpaceShareIconClicked
onShareButtonClicked = vm::onSpaceShareIconClicked,
navPanelState = vm.navPanelState.collectAsStateWithLifecycle().value
)
}

View file

@ -537,13 +537,6 @@ open class ObjectSetFragment :
lifecycleScope.subscribe(vm.isCustomizeViewPanelVisible) { isCustomizeViewPanelVisible ->
if (isCustomizeViewPanelVisible) showBottomPanel() else hideBottomPanel()
}
lifecycleScope.subscribe(vm.permission.filterNotNull()) { permission ->
if (permission.isOwnerOrEditor()) {
binding.bottomToolbar.setIsReadOnly(false)
} else {
binding.bottomToolbar.setIsReadOnly(true)
}
}
}
private fun setStatus(status: SpaceSyncAndP2PStatusState?) {
@ -1297,6 +1290,13 @@ open class ObjectSetFragment :
override fun onStart() {
super.onStart()
vm.navPanelState.onEach {
if (hasBinding) {
binding.bottomToolbar.setState(it)
}
}.launchIn(lifecycleScope)
jobs += lifecycleScope.subscribe(vm.commands) { observeCommands(it) }
jobs += lifecycleScope.subscribe(vm.header) { header ->
when(header) {

View file

@ -145,13 +145,11 @@ fun ScreenContent(
.align(BottomCenter)
.padding(bottom = 20.dp)) {
BottomNavigationMenu(
backClick = { vm.onPrevClicked() },
searchClick = onSearchClicked,
addDocClick = { vm.onAddClicked(null) },
addDocLongClick = onCreateObjectLongClicked,
backLongClick = vm::onBackLongClicked,
isOwnerOrEditor = uiState.isActionButtonVisible,
onShareButtonClicked = vm::onShareButtonClicked
onShareButtonClicked = vm::onShareButtonClicked,
state = vm.navPanelState.collectAsStateWithLifecycle().value
)
}
}

View file

@ -0,0 +1,4 @@
package com.anytypeio.anytype.core_ui.common
const val DEFAULT_DISABLED_ALPHA = 0.5f
const val FULL_ALPHA = 1f

View file

@ -17,6 +17,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.layout.ContentScale
@ -28,18 +29,50 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.compose.rememberAsyncImagePainter
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.common.DEFAULT_DISABLED_ALPHA
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
import com.anytypeio.anytype.core_ui.common.FULL_ALPHA
import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationDefaults.Height
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.foundation.noRippleCombinedClickable
import com.anytypeio.anytype.presentation.navigation.NavPanelState
import com.anytypeio.anytype.presentation.profile.ProfileIconView
@DefaultPreviews
@Composable
private fun NavBarPreviewOwner() {
BottomNavigationMenu(
searchClick = {},
addDocClick = {},
addDocLongClick = {},
state = NavPanelState.Default(
isCreateObjectButtonEnabled = true,
leftButtonState = NavPanelState.LeftButtonState.AddMembers(
isActive = true
)
)
)
}
@DefaultPreviews
@Composable
private fun NavBarPreviewReader() {
BottomNavigationMenu(
searchClick = {},
addDocClick = {},
addDocLongClick = {},
state = NavPanelState.Default(
isCreateObjectButtonEnabled = false,
leftButtonState = NavPanelState.LeftButtonState.ViewMembers
)
)
}
@DefaultPreviews
@Composable
private fun MyBottomNavigationMenu() {
BottomNavigationMenu(
backClick = {},
backLongClick = {},
searchClick = {},
addDocClick = {},
addDocLongClick = {},
@ -51,8 +84,6 @@ private fun MyBottomNavigationMenu() {
@Composable
private fun MyBottomViewerNavigationMenu() {
BottomNavigationMenu(
backClick = {},
backLongClick = {},
searchClick = {},
addDocClick = {},
addDocLongClick = {},
@ -63,8 +94,6 @@ private fun MyBottomViewerNavigationMenu() {
@Composable
fun BottomNavigationMenu(
modifier: Modifier = Modifier,
backClick: () -> Unit = {},
backLongClick: () -> Unit = {},
onShareButtonClicked: () -> Unit = {},
searchClick: () -> Unit = {},
addDocClick: () -> Unit = {},
@ -86,20 +115,29 @@ fun BottomNavigationMenu(
verticalAlignment = Alignment.CenterVertically
) {
MenuItem(
modifier = Modifier.width(72.dp).height(52.dp),
modifier = Modifier
.width(72.dp)
.height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_members_button),
res = BottomNavigationItem.MEMBERS.res,
res = if (isOwnerOrEditor)
BottomNavigationItem.ADD_MEMBERS.res
else
BottomNavigationItem.MEMBERS.res,
onClick = onShareButtonClicked
)
MenuItem(
modifier = Modifier.width(72.dp).height(52.dp),
modifier = Modifier
.width(72.dp)
.height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_search_button),
res = BottomNavigationItem.SEARCH.res,
onClick = searchClick
)
if (isOwnerOrEditor) {
MenuItem(
modifier = Modifier.width(72.dp).height(52.dp),
modifier = Modifier
.width(72.dp)
.height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_create_button),
res = BottomNavigationItem.ADD_DOC.res,
onClick = addDocClick,
@ -109,13 +147,107 @@ fun BottomNavigationMenu(
}
}
@Composable
fun BottomNavigationMenu(
state: NavPanelState,
modifier: Modifier = Modifier,
onShareButtonClicked: () -> Unit = {},
searchClick: () -> Unit = {},
addDocClick: () -> Unit = {},
addDocLongClick: () -> Unit = {}
) {
Row(
modifier = modifier
.height(Height)
.wrapContentWidth()
.background(
shape = RoundedCornerShape(16.dp),
color = colorResource(id = R.color.home_screen_toolbar_button)
)
/**
* Workaround for clicks through the bottom navigation menu.
*/
.noRippleClickable { },
verticalAlignment = Alignment.CenterVertically
) {
if (state is NavPanelState.Default) {
when (state.leftButtonState) {
is NavPanelState.LeftButtonState.AddMembers -> {
MenuItem(
modifier = Modifier
.width(72.dp)
.height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_members_button),
res = BottomNavigationItem.ADD_MEMBERS.res,
onClick = onShareButtonClicked
)
}
is NavPanelState.LeftButtonState.Comment -> {
// TODO
}
NavPanelState.LeftButtonState.ViewMembers -> {
MenuItem(
modifier = Modifier
.width(72.dp)
.height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_members_button),
res = BottomNavigationItem.MEMBERS.res,
onClick = onShareButtonClicked
)
}
}
} else {
MenuItem(
modifier = Modifier
.width(72.dp)
.height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_members_button),
res = BottomNavigationItem.MEMBERS.res,
onClick = onShareButtonClicked
)
}
MenuItem(
modifier = Modifier
.width(72.dp)
.height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_search_button),
res = BottomNavigationItem.SEARCH.res,
onClick = searchClick
)
MenuItem(
modifier = Modifier
.width(72.dp)
.height(52.dp)
.alpha(
if (state is NavPanelState.Default) {
if (state.isCreateObjectButtonEnabled)
FULL_ALPHA
else
DEFAULT_DISABLED_ALPHA
} else {
DEFAULT_DISABLED_ALPHA
}
)
,
contentDescription = stringResource(id = R.string.main_navigation_content_desc_create_button),
res = BottomNavigationItem.ADD_DOC.res,
onClick = addDocClick,
onLongClick = addDocLongClick,
enabled = (state is NavPanelState.Default && state.isCreateObjectButtonEnabled)
)
}
}
@Composable
private fun MenuItem(
modifier: Modifier,
contentDescription: String,
@DrawableRes res: Int,
onClick: () -> Unit = {},
onLongClick: () -> Unit = {}
onLongClick: () -> Unit = {},
enabled: Boolean = true
) {
val haptic = LocalHapticFeedback.current
Image(
@ -123,80 +255,29 @@ private fun MenuItem(
contentDescription = contentDescription,
contentScale = ContentScale.Inside,
modifier = modifier
.noRippleCombinedClickable(
onClick = onClick,
onLongClicked = {
haptic.performHapticFeedback(
HapticFeedbackType.LongPress
)
onLongClick()
}
)
.then(
if (enabled) {
Modifier
.noRippleCombinedClickable(
onClick = onClick,
onLongClicked = {
haptic.performHapticFeedback(
HapticFeedbackType.LongPress
)
onLongClick()
}
)
} else {
Modifier
}
)
)
}
@Composable
private fun ProfileMenuItem(
icon: ProfileIconView,
onClick: () -> Unit = {}
) {
when (icon) {
is ProfileIconView.Image -> {
Image(
painter = rememberAsyncImagePainter(
model = icon.url,
error = painterResource(id = R.drawable.ic_home_widget_space)
),
contentDescription = "Custom image profile",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(28.dp)
.clip(CircleShape)
.noRippleClickable { onClick() }
)
}
is ProfileIconView.Placeholder -> {
val name = icon.name
val nameFirstChar = if (name.isNullOrEmpty()) {
stringResource(id = R.string.account_default_name)
} else {
name.first().uppercaseChar().toString()
}
Box(
modifier = Modifier
.size(28.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.shape_primary))
.noRippleClickable { onClick() }
) {
Text(
text = nameFirstChar,
style = MaterialTheme.typography.h3.copy(
color = colorResource(id = R.color.text_white),
fontSize = 12.sp
),
modifier = Modifier.align(Alignment.Center)
)
}
}
else -> {
Box(
modifier = Modifier
.size(28.dp)
.clip(CircleShape)
.background(colorResource(id = R.color.shape_primary))
.noRippleClickable { onClick() }
)
}
}
}
private enum class BottomNavigationItem(@DrawableRes val res: Int) {
BACK(R.drawable.ic_nav_panel_back),
MEMBERS(R.drawable.ic_nav_panel_members),
ADD_MEMBERS(R.drawable.ic_nav_panel_add_member),
SEARCH(R.drawable.ic_nav_panel_search),
ADD_DOC(R.drawable.ic_nav_panel_plus)
}

View file

@ -6,8 +6,10 @@ import android.view.LayoutInflater
import android.widget.LinearLayout
import com.anytypeio.anytype.core_ui.databinding.WidgetMainBottomToolbarBinding
import com.anytypeio.anytype.core_ui.reactive.clicks
import com.anytypeio.anytype.core_utils.ext.gone
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.presentation.navigation.NavPanelState
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.common.DEFAULT_DISABLED_ALPHA
import com.anytypeio.anytype.core_ui.common.FULL_ALPHA
class MainBottomToolbar @JvmOverloads constructor(
context: Context,
@ -27,13 +29,55 @@ class MainBottomToolbar @JvmOverloads constructor(
fun addDocClicks() = binding.btnAddDoc.clicks()
fun shareClicks() = binding.btnShare.clicks()
fun setState(state: NavPanelState) {
when(state) {
is NavPanelState.Default -> {
setDefaultState(state)
}
NavPanelState.Init -> {
// Do nothing
}
}
}
fun setIsReadOnly(isReadOnly: Boolean) {
with(binding.btnAddDoc) {
if (isReadOnly)
gone()
else
visible()
private fun setDefaultState(state: NavPanelState.Default) {
setLeftButtonState(state)
setCreateButtonState(state)
}
private fun setCreateButtonState(state: NavPanelState.Default) {
if (state.isCreateObjectButtonEnabled) {
binding.icAddDoc.alpha = FULL_ALPHA
binding.btnAddDoc.isEnabled = true
} else {
binding.icAddDoc.alpha = DEFAULT_DISABLED_ALPHA
binding.btnAddDoc.isEnabled = false
}
}
private fun setLeftButtonState(state: NavPanelState.Default) {
when (val left = state.leftButtonState) {
is NavPanelState.LeftButtonState.AddMembers -> {
binding.icShare.setImageResource(
R.drawable.ic_nav_panel_add_member
)
if (left.isActive) {
binding.icShare.alpha = FULL_ALPHA
} else {
binding.icShare.alpha = DEFAULT_DISABLED_ALPHA
}
}
is NavPanelState.LeftButtonState.Comment -> {
}
NavPanelState.LeftButtonState.ViewMembers -> {
binding.icShare.setImageResource(
R.drawable.ic_nav_panel_add_member
)
binding.icShare.alpha = FULL_ALPHA
}
}
}
}

View file

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="33dp"
android:viewportWidth="32"
android:viewportHeight="33">
<path
android:pathData="M10.25,10.813a3.75,4 0,1 0,7.5 0a3.75,4 0,1 0,-7.5 0z"
android:fillColor="@color/glyph_active" />
<path
android:pathData="M16.826,24.313C16.605,23.687 16.484,23.014 16.484,22.313C16.484,20.482 17.304,18.843 18.597,17.742C17.293,16.841 15.709,16.313 14,16.313C10.064,16.313 6.788,19.115 6.084,22.821C5.93,23.635 6.616,24.313 7.445,24.313H16.826Z"
android:fillColor="@color/glyph_active"
android:fillType="evenOdd"/>
<path
android:pathData="M22.484,26.813C24.978,26.813 27,24.791 27,22.297C27,19.803 24.978,17.781 22.484,17.781C19.99,17.781 17.969,19.803 17.969,22.297C17.969,24.791 19.99,26.813 22.484,26.813ZM21.984,20.047C21.984,19.771 22.208,19.547 22.484,19.547C22.76,19.547 22.984,19.771 22.984,20.047V21.797H24.734C25.01,21.797 25.234,22.021 25.234,22.297C25.234,22.573 25.01,22.797 24.734,22.797H22.984V24.547C22.984,24.823 22.76,25.047 22.484,25.047C22.208,25.047 21.984,24.823 21.984,24.547V22.797H20.234C19.958,22.797 19.734,22.573 19.734,22.297C19.734,22.021 19.958,21.797 20.234,21.797H21.984V20.047Z"
android:fillColor="@color/glyph_active"
android:fillType="evenOdd"/>
</vector>

View file

@ -236,8 +236,6 @@ fun AllContentMainScreen(
onGlobalSearchClicked = onGlobalSearchClicked,
onAddDocClicked = onAddDocClicked,
onCreateObjectLongClicked = onCreateObjectLongClicked,
onBackClicked = onBackClicked,
onBackLongClicked = onBackLongClicked,
uiBottomMenu = uiBottomMenu,
onShareButtonClicked = onShareButtonClicked
)
@ -340,16 +338,12 @@ fun BottomMenu(
onGlobalSearchClicked: () -> Unit,
onAddDocClicked: () -> Unit,
onCreateObjectLongClicked: () -> Unit,
onBackClicked: () -> Unit,
onBackLongClicked: () -> Unit,
onShareButtonClicked: () -> Unit
) {
val isImeVisible = WindowInsets.ime.getBottom(LocalDensity.current) > 0
if (isImeVisible) return
BottomNavigationMenu(
modifier = modifier,
backClick = onBackClicked,
backLongClick = onBackLongClicked,
searchClick = onGlobalSearchClicked,
addDocClick = onAddDocClicked,
addDocLongClick = onCreateObjectLongClicked,

View file

@ -166,12 +166,6 @@ fun DateMainScreen(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 16.dp),
backClick = {
onDateEvent(DateEvent.NavigationWidget.OnBackClick)
},
backLongClick = {
onDateEvent(DateEvent.NavigationWidget.OnBackLongClick)
},
searchClick = {
onDateEvent(DateEvent.NavigationWidget.OnGlobalSearchClick)
},

View file

@ -257,6 +257,7 @@ import com.anytypeio.anytype.presentation.editor.model.OnEditorDatePickerEvent.O
import com.anytypeio.anytype.presentation.editor.model.OnEditorDatePickerEvent.OnTomorrowClick
import com.anytypeio.anytype.presentation.extension.getFileDetailsForBlock
import com.anytypeio.anytype.presentation.extension.getUrlForFileContent
import com.anytypeio.anytype.presentation.navigation.NavPanelState
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
import com.anytypeio.anytype.presentation.objects.getObjectTypeViewsForSBPage
import com.anytypeio.anytype.presentation.objects.getProperType
@ -431,6 +432,8 @@ class EditorViewModel(
*/
val mentionDatePicker = MutableStateFlow<EditorDatePickerState>(EditorDatePickerState.Hidden)
val navPanelState = permission.map { permission -> NavPanelState.fromPermission(permission) }
init {
Timber.i("EditorViewModel, init")
proceedWithObservingPermissions()

View file

@ -89,6 +89,7 @@ import com.anytypeio.anytype.presentation.extension.sendReorderWidgetEvent
import com.anytypeio.anytype.presentation.extension.sendSelectHomeTabEvent
import com.anytypeio.anytype.presentation.home.Command.ChangeWidgetType.Companion.UNDEFINED_LAYOUT_CODE
import com.anytypeio.anytype.presentation.navigation.DeepLinkToObjectDelegate
import com.anytypeio.anytype.presentation.navigation.NavPanelState
import com.anytypeio.anytype.presentation.navigation.NavigationViewModel
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
import com.anytypeio.anytype.presentation.search.Subscriptions
@ -107,7 +108,6 @@ import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction
import com.anytypeio.anytype.presentation.widgets.LinkWidgetContainer
import com.anytypeio.anytype.presentation.widgets.ListWidgetContainer
import com.anytypeio.anytype.presentation.widgets.SpaceBinWidgetContainer
import com.anytypeio.anytype.presentation.widgets.SpaceChatWidgetContainer
import com.anytypeio.anytype.presentation.widgets.SpaceWidgetContainer
import com.anytypeio.anytype.presentation.widgets.TreePath
import com.anytypeio.anytype.presentation.widgets.TreeWidgetBranchStateHolder
@ -186,7 +186,6 @@ class HomeScreenViewModel(
private val analytics: Analytics,
private val getWidgetSession: GetWidgetSession,
private val saveWidgetSession: SaveWidgetSession,
private val spaceGradientProvider: SpaceGradientProvider,
private val storeOfObjectTypes: StoreOfObjectTypes,
private val objectWatcher: ObjectWatcher,
private val spaceManager: SpaceManager,
@ -251,6 +250,8 @@ class HomeScreenViewModel(
val hasEditAccess = userPermissions.map { it?.isOwnerOrEditor() == true }
val navPanelState = MutableStateFlow<NavPanelState>(NavPanelState.Init)
private val widgetObjectPipeline = spaceManager
.observe()
.distinctUntilChanged()
@ -361,6 +362,18 @@ class HomeScreenViewModel(
proceedWithObservingDispatches()
proceedWithSettingUpShortcuts()
proceedWithViewStatePipeline()
proceedWithNavPanelState()
}
private fun proceedWithNavPanelState() {
viewModelScope.launch {
userPermissions
.map { permission ->
NavPanelState.fromPermission(permission)
}.collect {
navPanelState.value = it
}
}
}
private fun proceedWithViewStatePipeline() {
@ -2261,7 +2274,6 @@ class HomeScreenViewModel(
analytics = analytics,
getWidgetSession = getWidgetSession,
saveWidgetSession = saveWidgetSession,
spaceGradientProvider = spaceGradientProvider,
storeOfObjectTypes = storeOfObjectTypes,
storeOfRelations = storeOfRelations,
objectWatcher = objectWatcher,

View file

@ -0,0 +1,55 @@
package com.anytypeio.anytype.presentation.navigation
import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions
sealed class NavPanelState {
data object Init : NavPanelState()
data class Default(
val isCreateObjectButtonEnabled: Boolean,
val leftButtonState: LeftButtonState
) : NavPanelState()
sealed class LeftButtonState {
data object ViewMembers : LeftButtonState()
data class AddMembers(val isActive: Boolean): LeftButtonState()
data class Comment(val isActive: Boolean): LeftButtonState()
}
companion object {
fun fromPermission(permission: SpaceMemberPermissions?) : NavPanelState {
return when(permission) {
SpaceMemberPermissions.READER -> {
Default(
isCreateObjectButtonEnabled = false,
leftButtonState = LeftButtonState.ViewMembers
)
}
SpaceMemberPermissions.WRITER -> {
Default(
isCreateObjectButtonEnabled = true,
leftButtonState = LeftButtonState.ViewMembers
)
}
SpaceMemberPermissions.OWNER -> {
Default(
isCreateObjectButtonEnabled = true,
leftButtonState = LeftButtonState.AddMembers(
isActive = true
)
)
}
SpaceMemberPermissions.NO_PERMISSIONS -> {
Default(
isCreateObjectButtonEnabled = false,
leftButtonState = LeftButtonState.ViewMembers
)
}
else -> {
Init
}
}
}
}
}

View file

@ -76,6 +76,7 @@ import com.anytypeio.anytype.presentation.navigation.AppNavigation
import com.anytypeio.anytype.presentation.navigation.SupportNavigation
import com.anytypeio.anytype.core_models.SupportedLayouts
import com.anytypeio.anytype.core_models.TimeInMillis
import com.anytypeio.anytype.presentation.navigation.NavPanelState
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
import com.anytypeio.anytype.presentation.objects.isCreateObjectAllowed
import com.anytypeio.anytype.presentation.objects.isTemplatesAllowed
@ -225,6 +226,8 @@ class ObjectSetViewModel(
private val selectedTypeFlow: MutableStateFlow<ObjectWrapper.Type?> = MutableStateFlow(null)
val navPanelState = permission.map { permission -> NavPanelState.fromPermission(permission) }
init {
Timber.i("ObjectSetViewModel, init")

View file

@ -49,6 +49,7 @@ import com.anytypeio.anytype.presentation.extension.sendScreenHomeEvent
import com.anytypeio.anytype.presentation.home.OpenObjectNavigation
import com.anytypeio.anytype.presentation.home.navigation
import com.anytypeio.anytype.presentation.navigation.DefaultObjectView
import com.anytypeio.anytype.presentation.navigation.NavPanelState
import com.anytypeio.anytype.presentation.objects.ObjectAction
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
import com.anytypeio.anytype.presentation.objects.mapFileObjectToView
@ -119,6 +120,7 @@ class CollectionViewModel(
init {
Timber.i("CollectionViewModel, init, spaceId:${vmParams.spaceId.id}")
proceedWithObservingPermissions()
proceedWithNavPanelState()
val externalChannelEvents: Flow<Payload> = spaceManager
.observe()
.flatMapLatest { config ->
@ -148,6 +150,8 @@ class CollectionViewModel(
private var actionMode: ActionMode = ActionMode.Edit
private var subscription: Subscription = Subscription.None
val navPanelState = MutableStateFlow<NavPanelState>(NavPanelState.Init)
val uiState: StateFlow<Resultat<CollectionUiState>> =
combine(interactionMode, views, operationInProgress) { mode, views, operationInProgress ->
Resultat.success(
@ -189,6 +193,17 @@ class CollectionViewModel(
}
}
private fun proceedWithNavPanelState() {
viewModelScope.launch {
permission
.map { permission ->
NavPanelState.fromPermission(permission)
}.collect {
navPanelState.value = it
}
}
}
private suspend fun objectTypes(): StateFlow<List<ObjectWrapper.Type>> {
val params = GetObjectTypes.Params(
space = SpaceId(vmParams.spaceId.id),

View file

@ -197,9 +197,6 @@ class HomeScreenViewModelTest {
@Mock
lateinit var saveWidgetSession: SaveWidgetSession
@Mock
lateinit var spaceGradientProvider: SpaceGradientProvider
@Mock
lateinit var getWidgetSession: GetWidgetSession
@ -3036,7 +3033,6 @@ class HomeScreenViewModelTest {
analytics = analytics,
getWidgetSession = getWidgetSession,
saveWidgetSession = saveWidgetSession,
spaceGradientProvider = spaceGradientProvider,
storeOfObjectTypes = storeOfObjectTypes,
objectWatcher = objectWatcher,
setWidgetActiveView = setWidgetActiveView,