diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt index de31994eed..eb71b28993 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt @@ -2,8 +2,6 @@ package com.anytypeio.anytype.ui.home import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.animateContentSize -import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically @@ -11,6 +9,8 @@ import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -25,7 +25,10 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Text +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -52,14 +55,15 @@ 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.SectionType import com.anytypeio.anytype.presentation.widgets.ToIndex import com.anytypeio.anytype.presentation.widgets.TreePath import com.anytypeio.anytype.presentation.widgets.ViewId -import com.anytypeio.anytype.presentation.widgets.Widget import com.anytypeio.anytype.presentation.widgets.Widget.Source.Companion.SECTION_OBJECT_TYPE import com.anytypeio.anytype.presentation.widgets.Widget.Source.Companion.SECTION_PINNED import com.anytypeio.anytype.presentation.widgets.WidgetId import com.anytypeio.anytype.presentation.widgets.WidgetView +import com.anytypeio.anytype.ui.widgets.menu.getWidgetMenuItems import com.anytypeio.anytype.ui.widgets.types.AllContentWidgetCard import com.anytypeio.anytype.ui.widgets.types.BinWidgetCard import com.anytypeio.anytype.ui.widgets.types.DataViewListWidgetCard @@ -69,6 +73,7 @@ import com.anytypeio.anytype.ui.widgets.types.LinkWidgetCard import com.anytypeio.anytype.ui.widgets.types.ListWidgetCard import com.anytypeio.anytype.ui.widgets.types.SpaceChatWidgetCard import com.anytypeio.anytype.ui.widgets.types.TreeWidgetCard +import kotlinx.coroutines.delay import sh.calvin.reorderable.ReorderableItem import sh.calvin.reorderable.rememberReorderableLazyListState @@ -81,8 +86,7 @@ fun HomeScreen( onExpand: (TreePath) -> Unit, onWidgetElementClicked: (WidgetId, ObjectWrapper.Basic) -> Unit, onWidgetMenuTriggered: (WidgetId) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, - onBundledWidgetClicked: (WidgetId) -> Unit, + onWidgetSourceClicked: (WidgetId) -> Unit, onCreateWidget: () -> Unit, onWidgetMenuAction: (WidgetId, DropDownMenuAction) -> Unit, onChangeWidgetView: (WidgetId, ViewId) -> Unit, @@ -95,11 +99,10 @@ fun HomeScreen( onNavBarShareButtonClicked: () -> Unit, onObjectCheckboxClicked: (Id, Boolean) -> Unit, onMove: (List, FromIndex, ToIndex) -> Unit, - onCreateDataViewObject: (WidgetId, ViewId?) -> Unit, onCreateElement: (WidgetView) -> Unit = {}, onCreateNewTypeClicked: () -> Unit, onSectionClicked: (Id) -> Unit = {} - ) { +) { Box(modifier = modifier.fillMaxSize()) { WidgetList( @@ -108,14 +111,12 @@ fun HomeScreen( onWidgetMenuAction = onWidgetMenuAction, onWidgetElementClicked = onWidgetElementClicked, onWidgetSourceClicked = onWidgetSourceClicked, - onBundledWidgetHeaderClicked = onBundledWidgetClicked, onToggleExpandedWidgetState = onToggleExpandedWidgetState, mode = mode, onChangeWidgetView = onChangeWidgetView, onMove = onMove, onObjectCheckboxClicked = onObjectCheckboxClicked, onCreateWidget = onCreateWidget, - onCreateDataViewObject = onCreateDataViewObject, onCreateElement = onCreateElement, onWidgetMenuTriggered = onWidgetMenuTriggered, onCreateNewTypeClicked = onCreateNewTypeClicked, @@ -177,16 +178,14 @@ private fun WidgetList( onExpand: (TreePath) -> Unit, onWidgetMenuAction: (WidgetId, DropDownMenuAction) -> Unit, onWidgetElementClicked: (WidgetId, ObjectWrapper.Basic) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, + onWidgetSourceClicked: (WidgetId) -> Unit, onWidgetMenuTriggered: (WidgetId) -> Unit, - onBundledWidgetHeaderClicked: (WidgetId) -> Unit, onToggleExpandedWidgetState: (WidgetId) -> Unit, mode: InteractionMode, onChangeWidgetView: (WidgetId, ViewId) -> Unit, onMove: (List, FromIndex, ToIndex) -> Unit, onObjectCheckboxClicked: (Id, Boolean) -> Unit, onCreateWidget: () -> Unit, - onCreateDataViewObject: (WidgetId, ViewId?) -> Unit, onCreateElement: (WidgetView) -> Unit = {}, onCreateNewTypeClicked: () -> Unit, onSectionClicked: (Id) -> Unit = {} @@ -237,195 +236,295 @@ private fun WidgetList( ) { index, item -> when (item) { is WidgetView.Tree -> { - if (mode is InteractionMode.Edit) { - ReorderableItem(reorderableLazyListState, key = item.id) { isDragged -> - val alpha = animateFloatAsState(if (isDragged) 0.8f else 1.0f) - TreeWidgetItem( - modifier = DefaultDragAndDropModifier(view, onDragStoppedHandler), - index = index, - mode = mode, - alpha = alpha.value, - item = item, - onExpand = onExpand, - onWidgetMenuAction = onWidgetMenuAction, - onWidgetElementClicked = { obj -> - onWidgetElementClicked(item.id, obj) - }, - onObjectCheckboxClicked = onObjectCheckboxClicked, - onWidgetSourceClicked = onWidgetSourceClicked, - onToggleExpandedWidgetState = onToggleExpandedWidgetState, - onWidgetMenuTriggered = onWidgetMenuTriggered, - onCreateElement = onCreateElement - ) + val isCardMenuExpanded = remember { mutableStateOf(false) } + val menuItems = item.getWidgetMenuItems() + val isReorderEnabled = item.sectionType == SectionType.PINNED && mode !is InteractionMode.ReadOnly + + ReorderableItem( + enabled = isReorderEnabled, + state = reorderableLazyListState, + key = item.id + ) { isDragged -> + val hasStartedDragging = remember { mutableStateOf(false) } + + if (isReorderEnabled) { + LaunchedEffect(isDragged) { + if (isDragged) { + hasStartedDragging.value = true + delay(1000) + isCardMenuExpanded.value = false + } else if (hasStartedDragging.value) { + hasStartedDragging.value = false + } + } } - } else { - TreeWidgetItem( - index = index, + + val modifier = WidgetCardModifier( + isMenuExpanded = isCardMenuExpanded.value, + mode = mode, + onWidgetClicked = { onWidgetSourceClicked(item.id) }, + onWidgetLongClicked = { + isCardMenuExpanded.value = !isCardMenuExpanded.value + }, + dragModifier = if (isReorderEnabled) DefaultDragAndDropModifier( + view, + onDragStoppedHandler + ) else null, + shouldEnableLongClick = menuItems.isNotEmpty() && mode !is InteractionMode.ReadOnly + ) + + TreeWidgetCard( + modifier = modifier, mode = mode, - alpha = 1.0f, item = item, - onExpand = onExpand, - onWidgetMenuAction = onWidgetMenuAction, + onExpandElement = onExpand, onWidgetElementClicked = { obj -> onWidgetElementClicked(item.id, obj) }, - onObjectCheckboxClicked = onObjectCheckboxClicked, onWidgetSourceClicked = onWidgetSourceClicked, + onWidgetMenuClicked = onWidgetMenuTriggered, + onDropDownMenuAction = { action -> + onWidgetMenuAction(item.id, action) + }, onToggleExpandedWidgetState = onToggleExpandedWidgetState, - onWidgetMenuTriggered = onWidgetMenuTriggered, - onCreateElement = onCreateElement + onObjectCheckboxClicked = onObjectCheckboxClicked, + onCreateElement = onCreateElement, + menuItems = menuItems, + isCardMenuExpanded = isCardMenuExpanded ) } } + is WidgetView.Link -> { - if (mode is InteractionMode.Edit) { - ReorderableItem(reorderableLazyListState, key = item.id) { isDragged -> - val alpha = animateFloatAsState(if (isDragged) 0.8f else 1.0f) - LinkWidgetItem( - modifier = DefaultDragAndDropModifier(view, onDragStoppedHandler), - index = index, - mode = mode, - alpha = alpha.value, - item = item, - onWidgetMenuAction = onWidgetMenuAction, - onWidgetSourceClicked = onWidgetSourceClicked, - onObjectCheckboxClicked = onObjectCheckboxClicked - ) + val isCardMenuExpanded = remember { mutableStateOf(false) } + val menuItems = item.getWidgetMenuItems() + val isReorderEnabled = item.sectionType == SectionType.PINNED && mode !is InteractionMode.ReadOnly + + ReorderableItem( + enabled = isReorderEnabled, + state = reorderableLazyListState, + key = item.id + ) { isDragged -> + val hasStartedDragging = remember { mutableStateOf(false) } + + if (isReorderEnabled) { + LaunchedEffect(isDragged) { + if (isDragged) { + hasStartedDragging.value = true + delay(1000) + isCardMenuExpanded.value = false + } else if (hasStartedDragging.value) { + hasStartedDragging.value = false + } + } } - } else { - LinkWidgetItem( - index = index, + + val modifier = WidgetCardModifier( + isMenuExpanded = isCardMenuExpanded.value, mode = mode, - alpha = 1.0f, + onWidgetClicked = { onWidgetSourceClicked(item.id) }, + onWidgetLongClicked = { + isCardMenuExpanded.value = !isCardMenuExpanded.value + }, + dragModifier = if (isReorderEnabled) DefaultDragAndDropModifier( + view, + onDragStoppedHandler + ) else null, + shouldEnableLongClick = menuItems.isNotEmpty() && mode !is InteractionMode.ReadOnly + ) + + LinkWidgetCard( + modifier = modifier, item = item, - onWidgetMenuAction = onWidgetMenuAction, - onWidgetSourceClicked = onWidgetSourceClicked, - onObjectCheckboxClicked = onObjectCheckboxClicked + onDropDownMenuAction = { action -> + onWidgetMenuAction(item.id, action) + }, + onObjectCheckboxClicked = onObjectCheckboxClicked, + menuItems = menuItems, + isCardMenuExpanded = isCardMenuExpanded ) } } + is WidgetView.SetOfObjects -> { - if (mode is InteractionMode.Edit) { - ReorderableItem(reorderableLazyListState, key = item.id) { isDragged -> - val alpha = animateFloatAsState(if (isDragged) 0.8f else 1.0f) - SetOfObjectsItem( - modifier = DefaultDragAndDropModifier(view, onDragStoppedHandler), - index = index, - mode = mode, - alpha = alpha.value, - item = item, - onWidgetElementClicked = { obj -> - onWidgetElementClicked(item.id, obj) - }, - onWidgetMenuTriggered = onWidgetMenuTriggered, - onWidgetSourceClicked = onWidgetSourceClicked, - onWidgetMenuAction = onWidgetMenuAction, - onChangeWidgetView = onChangeWidgetView, - onToggleExpandedWidgetState = onToggleExpandedWidgetState, - onObjectCheckboxClicked = onObjectCheckboxClicked, - onCreateDataViewObject = onCreateDataViewObject, - onCreateElement = onCreateElement - ) + val isCardMenuExpanded = remember { mutableStateOf(false) } + val menuItems = item.getWidgetMenuItems() + val isReorderEnabled = item.sectionType == SectionType.PINNED && mode !is InteractionMode.ReadOnly + + ReorderableItem( + enabled = isReorderEnabled, + state = reorderableLazyListState, + key = item.id + ) { isDragged -> + val hasStartedDragging = remember { mutableStateOf(false) } + + if (isReorderEnabled) { + LaunchedEffect(isDragged) { + if (isDragged) { + hasStartedDragging.value = true + delay(1000) + isCardMenuExpanded.value = false + } else if (hasStartedDragging.value) { + hasStartedDragging.value = false + } + } } - } else { - SetOfObjectsItem( - index = index, + + val modifier = WidgetCardModifier( + isMenuExpanded = isCardMenuExpanded.value, mode = mode, - alpha = 1.0f, + onWidgetClicked = { onWidgetSourceClicked(item.id) }, + onWidgetLongClicked = { + isCardMenuExpanded.value = !isCardMenuExpanded.value + }, + dragModifier = if (isReorderEnabled) DefaultDragAndDropModifier( + view, + onDragStoppedHandler + ) else null, + shouldEnableLongClick = menuItems.isNotEmpty() && mode !is InteractionMode.ReadOnly + ) + + DataViewListWidgetCard( + modifier = modifier, item = item, - onWidgetElementClicked = { obj -> + mode = mode, + onWidgetObjectClicked = { obj -> onWidgetElementClicked(item.id, obj) }, - onWidgetMenuTriggered = onWidgetMenuTriggered, onWidgetSourceClicked = onWidgetSourceClicked, - onWidgetMenuAction = onWidgetMenuAction, + onWidgetMenuTriggered = onWidgetMenuTriggered, + onDropDownMenuAction = { action -> + onWidgetMenuAction(item.id, action) + }, onChangeWidgetView = onChangeWidgetView, onToggleExpandedWidgetState = onToggleExpandedWidgetState, onObjectCheckboxClicked = onObjectCheckboxClicked, - onCreateDataViewObject = onCreateDataViewObject, - onCreateElement = onCreateElement + onCreateElement = onCreateElement, + menuItems = menuItems, + isCardMenuExpanded = isCardMenuExpanded ) } } + is WidgetView.Gallery -> { - if (mode is InteractionMode.Edit) { - ReorderableItem(reorderableLazyListState, key = item.id) { isDragged -> - val alpha = animateFloatAsState(if (isDragged) 0.8f else 1.0f) - GalleryWidgetItem( - modifier = DefaultDragAndDropModifier(view, onDragStoppedHandler), - index = index, - mode = mode, - alpha = alpha.value, - item = item, - onWidgetElementClicked = { obj -> - onWidgetElementClicked(item.id, obj) - }, - onWidgetSourceClicked = onWidgetSourceClicked, - onWidgetMenuAction = onWidgetMenuAction, - onChangeWidgetView = onChangeWidgetView, - onToggleExpandedWidgetState = onToggleExpandedWidgetState, - onObjectCheckboxClicked = onObjectCheckboxClicked, - onWidgetMenuTriggered = onWidgetMenuTriggered - ) + val isCardMenuExpanded = remember { mutableStateOf(false) } + val menuItems = item.getWidgetMenuItems() + val isReorderEnabled = item.sectionType == SectionType.PINNED && mode !is InteractionMode.ReadOnly + + ReorderableItem( + enabled = isReorderEnabled, + state = reorderableLazyListState, + key = item.id + ) { isDragged -> + val hasStartedDragging = remember { mutableStateOf(false) } + + if (isReorderEnabled) { + LaunchedEffect(isDragged) { + if (isDragged) { + hasStartedDragging.value = true + delay(1000) + isCardMenuExpanded.value = false + } else if (hasStartedDragging.value) { + hasStartedDragging.value = false + } + } } - } else { - GalleryWidgetItem( - index = index, + + val modifier = WidgetCardModifier( + isMenuExpanded = isCardMenuExpanded.value, mode = mode, - alpha = 1.0f, + onWidgetClicked = { onWidgetSourceClicked(item.id) }, + onWidgetLongClicked = { + isCardMenuExpanded.value = !isCardMenuExpanded.value + }, + dragModifier = if (isReorderEnabled) DefaultDragAndDropModifier( + view, + onDragStoppedHandler + ) else null, + shouldEnableLongClick = menuItems.isNotEmpty() && mode !is InteractionMode.ReadOnly + ) + + GalleryWidgetCard( + modifier = modifier, item = item, - onWidgetElementClicked = { obj -> + mode = mode, + onWidgetObjectClicked = { obj -> onWidgetElementClicked(item.id, obj) }, onWidgetSourceClicked = onWidgetSourceClicked, - onWidgetMenuAction = onWidgetMenuAction, + onWidgetMenuTriggered = onWidgetMenuTriggered, + onDropDownMenuAction = { action -> + onWidgetMenuAction(item.id, action) + }, onChangeWidgetView = onChangeWidgetView, onToggleExpandedWidgetState = onToggleExpandedWidgetState, onObjectCheckboxClicked = onObjectCheckboxClicked, - onWidgetMenuTriggered = onWidgetMenuTriggered, - onCreateElement = onCreateElement + onCreateElement = onCreateElement, + menuItems = menuItems, + isCardMenuExpanded = isCardMenuExpanded ) } } + is WidgetView.ListOfObjects -> { - if (mode is InteractionMode.Edit) { - ReorderableItem(reorderableLazyListState, key = item.id) { isDragged -> - val alpha = animateFloatAsState(if (isDragged) 0.8f else 1.0f) - ListOfObjectsItem( - modifier = DefaultDragAndDropModifier(view, onDragStoppedHandler), - index = index, - mode = mode, - alpha = alpha.value, - item = item, - onWidgetElementClicked = { obj -> - onWidgetElementClicked(item.id, obj) - }, - onWidgetSourceClicked = onWidgetSourceClicked, - onWidgetMenuTriggered = onWidgetMenuTriggered, - onWidgetMenuAction = onWidgetMenuAction, - onToggleExpandedWidgetState = onToggleExpandedWidgetState, - onObjectCheckboxClicked = onObjectCheckboxClicked, - onCreateElement = onCreateElement - ) + val isCardMenuExpanded = remember { mutableStateOf(false) } + val menuItems = item.getWidgetMenuItems() + val isReorderEnabled = item.sectionType == SectionType.PINNED && mode !is InteractionMode.ReadOnly + + ReorderableItem( + enabled = isReorderEnabled, + state = reorderableLazyListState, + key = item.id + ) { isDragged -> + val hasStartedDragging = remember { mutableStateOf(false) } + + if (isReorderEnabled) { + LaunchedEffect(isDragged) { + if (isDragged) { + hasStartedDragging.value = true + delay(1000) + isCardMenuExpanded.value = false + } else if (hasStartedDragging.value) { + hasStartedDragging.value = false + } + } } - } else { - ListOfObjectsItem( - index = index, + + val modifier = WidgetCardModifier( + isMenuExpanded = isCardMenuExpanded.value, mode = mode, - alpha = 1.0f, + onWidgetClicked = { onWidgetSourceClicked(item.id) }, + onWidgetLongClicked = { + isCardMenuExpanded.value = !isCardMenuExpanded.value + }, + dragModifier = if (isReorderEnabled) DefaultDragAndDropModifier( + view, + onDragStoppedHandler + ) else null, + shouldEnableLongClick = menuItems.isNotEmpty() && mode !is InteractionMode.ReadOnly + ) + + ListWidgetCard( + modifier = modifier, item = item, - onWidgetElementClicked = { obj -> + mode = mode, + onWidgetObjectClicked = { obj -> onWidgetElementClicked(item.id, obj) }, onWidgetSourceClicked = onWidgetSourceClicked, onWidgetMenuTriggered = onWidgetMenuTriggered, - onWidgetMenuAction = onWidgetMenuAction, + onDropDownMenuAction = { action -> + onWidgetMenuAction(item.id, action) + }, onToggleExpandedWidgetState = onToggleExpandedWidgetState, onObjectCheckboxClicked = onObjectCheckboxClicked, - onCreateElement = onCreateElement + onCreateElement = onCreateElement, + menuItems = menuItems, + isCardMenuExpanded = isCardMenuExpanded ) } } + is WidgetView.Bin -> { BinWidgetCard( item = item, @@ -436,45 +535,57 @@ private fun WidgetList( onWidgetSourceClicked = onWidgetSourceClicked, ) } + is WidgetView.AllContent -> { - if (mode is InteractionMode.Edit) { - ReorderableItem(reorderableLazyListState, key = item.id) { isDragged -> - val alpha = animateFloatAsState(if (isDragged) 0.8f else 1.0f) - AllContentWidgetCard( - modifier = DefaultDragAndDropModifier(view, onDragStoppedHandler), - index = index, - mode = mode, - onWidgetClicked = { - onWidgetSourceClicked( - item.id, - Widget.Source.Bundled.AllObjects - ) - }, - onDropDownMenuAction = { action -> - onWidgetMenuAction(item.id, action) - }, - alpha = alpha.value, - widgetView = item - ) + val isCardMenuExpanded = remember { mutableStateOf(false) } + val menuItems = item.getWidgetMenuItems() + val isReorderEnabled = item.sectionType == SectionType.PINNED && mode !is InteractionMode.ReadOnly + + ReorderableItem( + enabled = isReorderEnabled, + state = reorderableLazyListState, + key = item.id + ) { isDragged -> + val hasStartedDragging = remember { mutableStateOf(false) } + + if (isReorderEnabled) { + LaunchedEffect(isDragged) { + if (isDragged) { + hasStartedDragging.value = true + delay(1000) + isCardMenuExpanded.value = false + } else if (hasStartedDragging.value) { + hasStartedDragging.value = false + } + } } - } else { - AllContentWidgetCard( - index = index, + + val modifier = WidgetCardModifier( + isMenuExpanded = isCardMenuExpanded.value, mode = mode, - onWidgetClicked = { - onWidgetSourceClicked( - item.id, - Widget.Source.Bundled.AllObjects - ) + onWidgetClicked = { onWidgetSourceClicked(item.id) }, + onWidgetLongClicked = { + isCardMenuExpanded.value = !isCardMenuExpanded.value }, + dragModifier = if (isReorderEnabled) DefaultDragAndDropModifier( + view, + onDragStoppedHandler + ) else null, + shouldEnableLongClick = menuItems.isNotEmpty() && mode !is InteractionMode.ReadOnly + ) + + AllContentWidgetCard( + modifier = modifier, + widgetView = item, onDropDownMenuAction = { action -> onWidgetMenuAction(item.id, action) }, - alpha = 1.0f, - widgetView = item + menuItems = menuItems, + isCardMenuExpanded = isCardMenuExpanded ) } } + is WidgetView.SpaceChat -> { SpaceChatWidgetCard( item = item, @@ -482,12 +593,13 @@ private fun WidgetList( unReadMentionCount = item.unreadMentionCount, unReadMessageCount = item.unreadMessageCount, isMuted = item.isMuted, - onWidgetClicked = { onWidgetSourceClicked(item.id, item.source) }, + onWidgetClicked = { onWidgetSourceClicked(item.id) }, onDropDownMenuAction = { action -> onWidgetMenuAction(item.id, action) } ) } + is WidgetView.EmptyState -> { if (mode !is InteractionMode.Edit) { EmptyStateWidgetScreen( @@ -505,6 +617,7 @@ private fun WidgetList( onSectionClicked = { onSectionClicked(SECTION_OBJECT_TYPE) } ) } + WidgetView.Section.Pinned -> { PinnedSectionHeader( onSectionClicked = { onSectionClicked(SECTION_PINNED) } @@ -519,194 +632,6 @@ private fun WidgetList( } } -@Composable -private fun ListOfObjectsItem( - modifier: Modifier = Modifier, - index: Int, - mode: InteractionMode, - alpha: Float, - item: WidgetView.ListOfObjects, - onWidgetElementClicked: (ObjectWrapper.Basic) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, - onWidgetMenuTriggered: (WidgetId) -> Unit, - onWidgetMenuAction: (WidgetId, DropDownMenuAction) -> Unit, - onToggleExpandedWidgetState: (WidgetId) -> Unit, - onObjectCheckboxClicked: (Id, Boolean) -> Unit, - onCreateElement: (WidgetView) -> Unit = {} -) { - Box( - modifier = modifier - .animateContentSize() - .fillMaxWidth() - .padding(top = if (index == 0) 6.dp else 0.dp) - .alpha(alpha) - ) { - ListWidgetCard( - item = item, - mode = mode, - onWidgetObjectClicked = onWidgetElementClicked, - onWidgetSourceClicked = onWidgetSourceClicked, - onDropDownMenuAction = { action -> - onWidgetMenuAction(item.id, action) - }, - onToggleExpandedWidgetState = onToggleExpandedWidgetState, - onObjectCheckboxClicked = onObjectCheckboxClicked, - onCreateElement = onCreateElement, - onWidgetMenuTriggered = onWidgetMenuTriggered - ) - } -} - -@Composable -private fun SetOfObjectsItem( - modifier: Modifier = Modifier, - index: Int, - mode: InteractionMode, - alpha: Float, - item: WidgetView.SetOfObjects, - onWidgetElementClicked: (ObjectWrapper.Basic) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, - onWidgetMenuTriggered: (WidgetId) -> Unit, - onWidgetMenuAction: (WidgetId, DropDownMenuAction) -> Unit, - onChangeWidgetView: (WidgetId, ViewId) -> Unit, - onToggleExpandedWidgetState: (WidgetId) -> Unit, - onObjectCheckboxClicked: (Id, Boolean) -> Unit, - onCreateDataViewObject: (WidgetId, ViewId?) -> Unit, - onCreateElement: (WidgetView) -> Unit = {} -) { - Box( - modifier = modifier - .animateContentSize() - .fillMaxWidth() - .padding(top = if (index == 0) 6.dp else 0.dp) - .alpha(alpha) - ) { - DataViewListWidgetCard( - item = item, - onWidgetObjectClicked = onWidgetElementClicked, - onWidgetSourceClicked = onWidgetSourceClicked, - onWidgetMenuTriggered = onWidgetMenuTriggered, - onDropDownMenuAction = { action -> - onWidgetMenuAction(item.id, action) - }, - onChangeWidgetView = onChangeWidgetView, - onToggleExpandedWidgetState = onToggleExpandedWidgetState, - mode = mode, - onObjectCheckboxClicked = onObjectCheckboxClicked, - onCreateElement = onCreateElement - ) - } -} - -@Composable -private fun GalleryWidgetItem( - modifier: Modifier = Modifier, - index: Int, - mode: InteractionMode, - alpha: Float, - item: WidgetView.Gallery, - onWidgetElementClicked: (ObjectWrapper.Basic) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, - onWidgetMenuTriggered: (WidgetId) -> Unit, - onWidgetMenuAction: (WidgetId, DropDownMenuAction) -> Unit, - onChangeWidgetView: (WidgetId, ViewId) -> Unit, - onToggleExpandedWidgetState: (WidgetId) -> Unit, - onObjectCheckboxClicked: (Id, Boolean) -> Unit, - onCreateElement: (WidgetView) -> Unit = {} -) { - Box( - modifier = modifier - .animateContentSize() - .fillMaxWidth() - .padding(top = if (index == 0) 6.dp else 0.dp) - .alpha(alpha) - ) { - GalleryWidgetCard( - item = item, - onWidgetObjectClicked = onWidgetElementClicked, - onWidgetSourceClicked = onWidgetSourceClicked, - onDropDownMenuAction = { action -> - onWidgetMenuAction(item.id, action) - }, - onChangeWidgetView = onChangeWidgetView, - onToggleExpandedWidgetState = onToggleExpandedWidgetState, - mode = mode, - onObjectCheckboxClicked = onObjectCheckboxClicked, - onWidgetMenuTriggered = onWidgetMenuTriggered, - onCreateElement = onCreateElement - ) - } -} - -@Composable -private fun LinkWidgetItem( - modifier: Modifier = Modifier, - index: Int, - mode: InteractionMode, - alpha: Float, - item: WidgetView.Link, - onWidgetMenuAction: (WidgetId, DropDownMenuAction) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, - onObjectCheckboxClicked: (Id, Boolean) -> Unit -) { - Box( - modifier = modifier - .fillMaxWidth() - .padding(top = if (index == 0) 6.dp else 0.dp) - .alpha(alpha) - ) { - LinkWidgetCard( - item = item, - onDropDownMenuAction = { action -> - onWidgetMenuAction(item.id, action) - }, - onWidgetSourceClicked = onWidgetSourceClicked, - hasReadOnlyAccess = mode is InteractionMode.ReadOnly, - onObjectCheckboxClicked = onObjectCheckboxClicked - ) - } -} - -@Composable -private fun TreeWidgetItem( - modifier: Modifier = Modifier, - index: Int, - mode: InteractionMode, - alpha: Float, - item: WidgetView.Tree, - onExpand: (TreePath) -> Unit, - onWidgetMenuTriggered: (WidgetId) -> Unit, - onWidgetMenuAction: (WidgetId, DropDownMenuAction) -> Unit, - onWidgetElementClicked: (ObjectWrapper.Basic) -> Unit, - onObjectCheckboxClicked: (Id, Boolean) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, - onToggleExpandedWidgetState: (WidgetId) -> Unit, - onCreateElement: (WidgetView) -> Unit -) { - Box( - modifier = modifier - .animateContentSize() - .fillMaxWidth() - .padding(top = if (index == 0) 6.dp else 0.dp) - .alpha(alpha) - ) { - TreeWidgetCard( - item = item, - onExpandElement = onExpand, - onDropDownMenuAction = { action -> - onWidgetMenuAction(item.id, action) - }, - onWidgetElementClicked = onWidgetElementClicked, - onObjectCheckboxClicked = onObjectCheckboxClicked, - onWidgetSourceClicked = onWidgetSourceClicked, - onToggleExpandedWidgetState = onToggleExpandedWidgetState, - onCreateElement = onCreateElement, - mode = mode, - onWidgetMenuClicked = onWidgetMenuTriggered - ) - } -} - @Composable fun WidgetEditModeButton( text: String, @@ -782,4 +707,51 @@ private fun PinnedSectionHeader( color = colorResource(id = R.color.control_transparent_secondary) ) } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun WidgetCardModifier( + isMenuExpanded: Boolean, + mode: InteractionMode, + onWidgetClicked: () -> Unit, + onWidgetLongClicked: () -> Unit, + dragModifier: Modifier? = null, + shouldEnableLongClick: Boolean = true +): Modifier { + val haptic = LocalHapticFeedback.current + + var modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp) + .alpha(if (isMenuExpanded) 0.8f else 1f) + .background( + shape = RoundedCornerShape(16.dp), + color = colorResource(id = R.color.dashboard_card_background) + ) + .then( + if (mode is InteractionMode.ReadOnly) { + Modifier.noRippleClickable { onWidgetClicked() } + } else { + if (shouldEnableLongClick) { + Modifier.combinedClickable( + onClick = { onWidgetClicked() }, + onLongClick = { + onWidgetLongClicked() + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + }, + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) + } else { + Modifier.noRippleClickable { onWidgetClicked() } + } + } + ) + + if (dragModifier != null) { + modifier = modifier.then(dragModifier) + } + + return modifier } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt index 0e959d17f7..0c852f80b4 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt @@ -221,10 +221,8 @@ class HomeScreenFragment : Fragment(), onCreateNewObjectLongClicked = throttledClick( onClick = { vm.onCreateNewObjectLongClicked() } ), - onBundledWidgetClicked = vm::onBundledWidgetClicked, onMove = vm::onMove, onObjectCheckboxClicked = vm::onObjectCheckboxClicked, - onCreateDataViewObject = {_, _ -> }, onNavBarShareButtonClicked = vm::onNavBarShareIconClicked, navPanelState = vm.navPanelState.collectAsStateWithLifecycle().value, onHomeButtonClicked = vm::onHomeButtonClicked, diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/menu/WidgetDropDownMenu.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/menu/WidgetDropDownMenu.kt index f9c93b7c4e..b953b5eb1a 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/menu/WidgetDropDownMenu.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/menu/WidgetDropDownMenu.kt @@ -28,41 +28,55 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_models.ObjectType -import com.anytypeio.anytype.core_models.ObjectWrapper -import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_ui.common.DefaultPreviews import com.anytypeio.anytype.core_ui.views.BodyRegular -import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction import com.anytypeio.anytype.presentation.widgets.SectionType import com.anytypeio.anytype.presentation.widgets.Widget +import com.anytypeio.anytype.presentation.widgets.WidgetId import com.anytypeio.anytype.presentation.widgets.WidgetView +/** + * Represents a menu item that can be displayed in the widget long-click menu. + */ +sealed class WidgetMenuItem { + data class CreateObjectOfType(val widgetId: WidgetId) : WidgetMenuItem() + data object ChangeWidgetType : WidgetMenuItem() + data object RemoveWidget : WidgetMenuItem() +} + @Composable fun WidgetLongClickMenu( - widgetView: WidgetView, + menuItems: List, isCardMenuExpanded: MutableState, onDropDownMenuAction: (DropDownMenuAction) -> Unit ) { - when (widgetView.sectionType) { - SectionType.PINNED -> { - DropdownMenu( - modifier = Modifier.width(254.dp), - expanded = isCardMenuExpanded.value, - onDismissRequest = { isCardMenuExpanded.value = false }, - containerColor = colorResource(R.color.background_secondary), - shape = RoundedCornerShape(12.dp), - tonalElevation = 8.dp, - offset = DpOffset( - x = 16.dp, - y = 8.dp - ) - ) { - if (widgetView.canCreateObjectOfType) { + if (menuItems.isEmpty()) { + // No menu to show, ensure it's closed + if (isCardMenuExpanded.value) { + isCardMenuExpanded.value = false + } + return + } + + DropdownMenu( + modifier = Modifier.width(254.dp), + expanded = isCardMenuExpanded.value, + onDismissRequest = { isCardMenuExpanded.value = false }, + containerColor = colorResource(R.color.background_secondary), + shape = RoundedCornerShape(12.dp), + tonalElevation = 8.dp, + offset = DpOffset( + x = 16.dp, + y = 8.dp + ) + ) { + menuItems.forEachIndexed { index, menuItem -> + when (menuItem) { + is WidgetMenuItem.CreateObjectOfType -> { DropdownMenuItem( onClick = { - onDropDownMenuAction(DropDownMenuAction.CreateObjectOfType(widgetView.id)).also { + onDropDownMenuAction(DropDownMenuAction.CreateObjectOfType(menuItem.widgetId)).also { isCardMenuExpanded.value = false } }, @@ -88,12 +102,15 @@ fun WidgetLongClickMenu( } } ) - Divider( - thickness = 8.dp, - color = colorResource(id = R.color.shape_primary) - ) + // Add thick divider after "Create Object" if not the last item + if (index < menuItems.lastIndex) { + Divider( + thickness = 8.dp, + color = colorResource(id = R.color.shape_primary) + ) + } } - if(widgetView.canChangeWidgetType()) { + is WidgetMenuItem.ChangeWidgetType -> { DropdownMenuItem( onClick = { onDropDownMenuAction(DropDownMenuAction.ChangeWidgetType).also { @@ -122,59 +139,25 @@ fun WidgetLongClickMenu( } } ) + // Add thin divider after "Change Type" if not the last item + if (index < menuItems.lastIndex) { + Divider( + thickness = 0.5.dp, + color = colorResource(id = R.color.shape_primary) + ) + } } - Divider( - thickness = 0.5.dp, - color = colorResource(id = R.color.shape_primary) - ) - DropdownMenuItem( - onClick = { - onDropDownMenuAction(DropDownMenuAction.RemoveWidget).also { - isCardMenuExpanded.value = false - } - }, - text = { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() - ) { - Text( - modifier = Modifier.weight(1f), - style = BodyRegular, - color = colorResource(id = R.color.text_primary), - text = stringResource(R.string.widget_unpin) - ) - Image( - painter = painterResource(id = R.drawable.ic_unpin_24), - contentDescription = "Unpin widget icon", - modifier = Modifier.size(24.dp), - colorFilter = ColorFilter.tint( - colorResource(id = R.color.text_primary) - ) - ) - } + is WidgetMenuItem.RemoveWidget -> { + // Add thin divider before "Remove/Unpin" if not the first item + if (index > 0) { + Divider( + thickness = 0.5.dp, + color = colorResource(id = R.color.shape_primary) + ) } - ) - } - } - - SectionType.TYPES -> { - if (widgetView.canCreateObjectOfType) { - DropdownMenu( - modifier = Modifier.width(254.dp), - expanded = isCardMenuExpanded.value, - onDismissRequest = { isCardMenuExpanded.value = false }, - containerColor = colorResource(R.color.background_secondary), - shape = RoundedCornerShape(12.dp), - tonalElevation = 8.dp, - offset = DpOffset( - x = 16.dp, - y = 8.dp - ) - ) { DropdownMenuItem( onClick = { - onDropDownMenuAction(DropDownMenuAction.CreateObjectOfType(widgetView.id)).also { + onDropDownMenuAction(DropDownMenuAction.RemoveWidget).also { isCardMenuExpanded.value = false } }, @@ -183,15 +166,15 @@ fun WidgetLongClickMenu( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth() ) { - androidx.compose.material.Text( + Text( modifier = Modifier.weight(1f), style = BodyRegular, color = colorResource(id = R.color.text_primary), - text = stringResource(R.string.widgets_menu_new_object_type) + text = stringResource(R.string.widget_unpin) ) Image( - painter = painterResource(id = R.drawable.ic_menu_item_create), - contentDescription = "New object icon", + painter = painterResource(id = R.drawable.ic_unpin_24), + contentDescription = "Unpin widget icon", modifier = Modifier.size(24.dp), colorFilter = ColorFilter.tint( colorResource(id = R.color.text_primary) @@ -201,14 +184,8 @@ fun WidgetLongClickMenu( } ) } - } else { - isCardMenuExpanded.value = false } } - - null -> { - //do nothing - } } } @@ -238,6 +215,41 @@ private fun WidgetView.canChangeWidgetType(): Boolean { } } +/** + * Determines which menu items should be shown for this widget. + * Returns a list of menu items, or an empty list if no menu should be displayed. + */ +fun WidgetView.getWidgetMenuItems(): List { + return when (sectionType) { + SectionType.PINNED -> { + buildList { + // Add "Create Object of Type" if applicable + if (canCreateObjectOfType) { + add(WidgetMenuItem.CreateObjectOfType(id)) + } + // Add "Change Widget Type" if applicable + if (canChangeWidgetType()) { + add(WidgetMenuItem.ChangeWidgetType) + } + // Always add "Unpin" for pinned widgets + add(WidgetMenuItem.RemoveWidget) + } + } + SectionType.TYPES -> { + // TYPES widgets only show menu if they can create objects + if (canCreateObjectOfType) { + listOf(WidgetMenuItem.CreateObjectOfType(id)) + } else { + emptyList() + } + } + null -> { + // No section type means no menu + emptyList() + } + } +} + @Composable fun BinWidgetMenu( widgetView: WidgetView, @@ -300,28 +312,9 @@ fun WidgetLongClickMenuPreview_PinnedSection_WithCreateOption() { .background(Color.Gray.copy(alpha = 0.1f)) ) { WidgetLongClickMenu( - widgetView = WidgetView.SetOfObjects( - id = "widget-1", - icon = ObjectIcon.None, - source = Widget.Source.Default( - obj = ObjectWrapper.Basic( - mapOf( - Relations.ID to "obj-1", - Relations.UNIQUE_KEY to "Obj 1", - Relations.LAYOUT to ObjectType.Layout.OBJECT_TYPE.code.toDouble(), - Relations.RECOMMENDED_LAYOUT to ObjectType.Layout.BASIC.code.toDouble() - ) - ) - ), - elements = emptyList(), - isExpanded = true, - isCompact = false, - sectionType = SectionType.PINNED, - tabs = emptyList(), - name = WidgetView.Name.Default("My Widget") - ), isCardMenuExpanded = isExpanded, - onDropDownMenuAction = { /* Preview action */ } + onDropDownMenuAction = { /* Preview action */ }, + menuItems = emptyList() ) } } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/AllContentWidget.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/AllContentWidget.kt index e7eeef763b..07476eba9b 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/AllContentWidget.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/AllContentWidget.kt @@ -1,24 +1,16 @@ package com.anytypeio.anytype.ui.widgets.types -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember 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.platform.LocalHapticFeedback import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -26,58 +18,24 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.anytypeio.anytype.R import com.anytypeio.anytype.core_ui.views.HeadlineSubheading -import com.anytypeio.anytype.presentation.home.InteractionMode import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction import com.anytypeio.anytype.presentation.widgets.WidgetView import com.anytypeio.anytype.ui.widgets.menu.WidgetLongClickMenu +import com.anytypeio.anytype.ui.widgets.menu.WidgetMenuItem -@OptIn(ExperimentalFoundationApi::class) @Composable fun AllContentWidgetCard( - modifier: Modifier = Modifier, - index: Int, widgetView: WidgetView, - mode: InteractionMode, - onWidgetClicked: () -> Unit = {}, - onDropDownMenuAction: (DropDownMenuAction) -> Unit = {}, - alpha: Float, + onDropDownMenuAction: (DropDownMenuAction) -> Unit, + menuItems: List = emptyList(), + isCardMenuExpanded: MutableState = mutableStateOf(false), + modifier: Modifier = Modifier ) { - val haptic = LocalHapticFeedback.current - val isCardMenuExpanded = remember { - mutableStateOf(false) - } - Box( - modifier = modifier - .fillMaxWidth() - .padding(top = if (index == 0) 6.dp else 0.dp) - .alpha(alpha) - ) { + Box(modifier = modifier) { Box( modifier = Modifier - .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp) .fillMaxWidth() .height(52.dp) - .background( - shape = RoundedCornerShape(16.dp), - color = colorResource(id = R.color.dashboard_card_background) - ) - .clip(RoundedCornerShape(16.dp)) - .then( - if (mode !is InteractionMode.Edit) { - Modifier.combinedClickable( - onClick = { - onWidgetClicked() - }, - onLongClick = { - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - isCardMenuExpanded.value = true - } - ) - } else { - Modifier - } - ) - .alpha(alpha) ) { Image( painter = painterResource(id = R.drawable.ic_widget_all_content), @@ -99,7 +57,7 @@ fun AllContentWidgetCard( ) } WidgetLongClickMenu( - widgetView = widgetView, + menuItems = menuItems, isCardMenuExpanded = isCardMenuExpanded, onDropDownMenuAction = onDropDownMenuAction ) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/BinWidgetCard.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/BinWidgetCard.kt index af91809340..d01d76f3d9 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/BinWidgetCard.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/BinWidgetCard.kt @@ -31,7 +31,6 @@ import com.anytypeio.anytype.core_ui.foundation.noRippleClickable import com.anytypeio.anytype.core_ui.views.HeadlineSubheading import com.anytypeio.anytype.presentation.home.InteractionMode import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction -import com.anytypeio.anytype.presentation.widgets.Widget import com.anytypeio.anytype.presentation.widgets.WidgetId import com.anytypeio.anytype.presentation.widgets.WidgetView import com.anytypeio.anytype.ui.widgets.menu.BinWidgetMenu @@ -42,7 +41,7 @@ fun BinWidgetCard( item: WidgetView.Bin, mode: InteractionMode, hasReadOnlyAccess: Boolean = false, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, + onWidgetSourceClicked: (WidgetId) -> Unit, onDropDownMenuAction: (DropDownMenuAction) -> Unit ) { val isCardMenuExpanded = remember { @@ -64,11 +63,11 @@ fun BinWidgetCard( .then( if (hasReadOnlyAccess) { Modifier.noRippleClickable { - onWidgetSourceClicked(item.id, item.source) + onWidgetSourceClicked(item.id) } } else { Modifier.combinedClickable( - onClick = { onWidgetSourceClicked(item.id, item.source) }, + onClick = { onWidgetSourceClicked(item.id) }, onLongClick = { isCardMenuExpanded.value = !isCardMenuExpanded.value haptic.performHapticFeedback(HapticFeedbackType.LongPress) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/DataViewWidget.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/DataViewWidget.kt index d19169a892..2ddea825ed 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/DataViewWidget.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/DataViewWidget.kt @@ -22,11 +22,10 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Divider import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember 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.graphics.Brush import androidx.compose.ui.graphics.Color @@ -57,41 +56,25 @@ import com.anytypeio.anytype.presentation.widgets.Widget import com.anytypeio.anytype.presentation.widgets.WidgetId import com.anytypeio.anytype.presentation.widgets.WidgetView import com.anytypeio.anytype.ui.widgets.menu.WidgetLongClickMenu +import com.anytypeio.anytype.ui.widgets.menu.WidgetMenuItem @Composable fun DataViewListWidgetCard( item: WidgetView.SetOfObjects, mode: InteractionMode, onWidgetObjectClicked: (ObjectWrapper.Basic) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, + onWidgetSourceClicked: (WidgetId) -> Unit, onWidgetMenuTriggered: (WidgetId) -> Unit, onDropDownMenuAction: (DropDownMenuAction) -> Unit, onChangeWidgetView: (WidgetId, ViewId) -> Unit, onToggleExpandedWidgetState: (WidgetId) -> Unit, onObjectCheckboxClicked: (Id, Boolean) -> Unit, - onCreateElement: (WidgetView) -> Unit = {} + onCreateElement: (WidgetView) -> Unit = {}, + menuItems: List = emptyList(), + isCardMenuExpanded: MutableState = mutableStateOf(false), + modifier: Modifier = Modifier ) { - val isCardMenuExpanded = remember { - mutableStateOf(false) - } - Box( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp) - .alpha(if (isCardMenuExpanded.value) 0.8f else 1f) - .background( - shape = RoundedCornerShape(16.dp), - color = colorResource(id = R.color.dashboard_card_background) - ) - .then( - if (mode is InteractionMode.Edit) - Modifier.noRippleClickable { - isCardMenuExpanded.value = !isCardMenuExpanded.value - } - else - Modifier - ) - ) { + Box(modifier = modifier) { Column( modifier = Modifier .fillMaxWidth() @@ -103,7 +86,7 @@ fun DataViewListWidgetCard( isCardMenuExpanded = isCardMenuExpanded, onWidgetHeaderClicked = { if (mode !is InteractionMode.Edit) { - onWidgetSourceClicked(item.id, item.source) + onWidgetSourceClicked(item.id) } }, onExpandElement = { onToggleExpandedWidgetState(item.id) }, @@ -165,7 +148,7 @@ fun DataViewListWidgetCard( } WidgetLongClickMenu( - widgetView = item, + menuItems = menuItems, isCardMenuExpanded = isCardMenuExpanded, onDropDownMenuAction = onDropDownMenuAction ) @@ -177,33 +160,18 @@ fun GalleryWidgetCard( item: WidgetView.Gallery, mode: InteractionMode, onWidgetObjectClicked: (ObjectWrapper.Basic) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, + onWidgetSourceClicked: (WidgetId) -> Unit, onWidgetMenuTriggered: (WidgetId) -> Unit, onDropDownMenuAction: (DropDownMenuAction) -> Unit, onChangeWidgetView: (WidgetId, ViewId) -> Unit, onToggleExpandedWidgetState: (WidgetId) -> Unit, onObjectCheckboxClicked: (Id, Boolean) -> Unit, - onCreateElement: (WidgetView) -> Unit + onCreateElement: (WidgetView) -> Unit, + menuItems: List = emptyList(), + isCardMenuExpanded: MutableState = mutableStateOf(false), + modifier: Modifier = Modifier ) { - val isCardMenuExpanded = remember { - mutableStateOf(false) - } - val isHeaderMenuExpanded = remember { - mutableStateOf(false) - } - Box( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp) - .alpha(if (isCardMenuExpanded.value || isHeaderMenuExpanded.value) 0.8f else 1f) - .background( - shape = RoundedCornerShape(16.dp), - color = colorResource(id = R.color.dashboard_card_background) - ) - .noRippleClickable { - isCardMenuExpanded.value = !isCardMenuExpanded.value - } - ) { + Box(modifier = modifier) { Column( modifier = Modifier .fillMaxWidth() @@ -215,7 +183,7 @@ fun GalleryWidgetCard( isCardMenuExpanded = isCardMenuExpanded, onWidgetHeaderClicked = { if (mode !is InteractionMode.Edit) { - onWidgetSourceClicked(item.id, item.source) + onWidgetSourceClicked(item.id) } }, onExpandElement = { onToggleExpandedWidgetState(item.id) }, @@ -267,7 +235,7 @@ fun GalleryWidgetCard( ) .clip(RoundedCornerShape(8.dp)) .clickable { - onWidgetSourceClicked(item.id, item.source) + onWidgetSourceClicked(item.id) } ) { Text( @@ -300,7 +268,7 @@ fun GalleryWidgetCard( } } WidgetLongClickMenu( - widgetView = item, + menuItems = menuItems, isCardMenuExpanded = isCardMenuExpanded, onDropDownMenuAction = onDropDownMenuAction ) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/LinkWidget.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/LinkWidget.kt index 92198b6442..f5842b6330 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/LinkWidget.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/LinkWidget.kt @@ -1,81 +1,38 @@ package com.anytypeio.anytype.ui.widgets.types -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background -import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.hapticfeedback.HapticFeedbackType -import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.colorResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.anytypeio.anytype.R import com.anytypeio.anytype.core_models.Id -import com.anytypeio.anytype.core_ui.foundation.noRippleClickable import com.anytypeio.anytype.core_ui.views.HeadlineSubheading import com.anytypeio.anytype.core_ui.widgets.ListWidgetObjectIcon import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction -import com.anytypeio.anytype.presentation.widgets.Widget -import com.anytypeio.anytype.presentation.widgets.WidgetId import com.anytypeio.anytype.presentation.widgets.WidgetView import com.anytypeio.anytype.ui.widgets.menu.WidgetLongClickMenu +import com.anytypeio.anytype.ui.widgets.menu.WidgetMenuItem -@OptIn(ExperimentalFoundationApi::class) @Composable fun LinkWidgetCard( item: WidgetView.Link, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, onDropDownMenuAction: (DropDownMenuAction) -> Unit, - hasReadOnlyAccess: Boolean = false, - onObjectCheckboxClicked: (Id, Boolean) -> Unit + onObjectCheckboxClicked: (Id, Boolean) -> Unit, + menuItems: List = emptyList(), + isCardMenuExpanded: MutableState = mutableStateOf(false), + modifier: Modifier = Modifier ) { - val isCardMenuExpanded = remember { - mutableStateOf(false) - } - val isHeaderMenuExpanded = remember { - mutableStateOf(false) - } - val haptic = LocalHapticFeedback.current - Box( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp) - .alpha(if (isCardMenuExpanded.value || isHeaderMenuExpanded.value) 0.8f else 1f) - .background( - shape = RoundedCornerShape(16.dp), - color = colorResource(id = R.color.dashboard_card_background) - ) - .then( - if (hasReadOnlyAccess) { - Modifier.noRippleClickable { - onWidgetSourceClicked(item.id, item.source) - } - } else { - Modifier.combinedClickable( - onClick = { onWidgetSourceClicked(item.id, item.source) }, - onLongClick = { - isCardMenuExpanded.value = !isCardMenuExpanded.value - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - }, - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) - } - ) - ) { + Box(modifier = modifier) { Row ( Modifier @@ -107,7 +64,7 @@ fun LinkWidgetCard( ) } WidgetLongClickMenu( - widgetView = item, + menuItems = menuItems, isCardMenuExpanded = isCardMenuExpanded, onDropDownMenuAction = onDropDownMenuAction ) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/ListWidget.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/ListWidget.kt index b1485bdbd2..bfb28d9ab5 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/ListWidget.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/ListWidget.kt @@ -1,6 +1,5 @@ package com.anytypeio.anytype.ui.widgets.types -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -8,15 +7,13 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Divider import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -28,61 +25,41 @@ import com.anytypeio.anytype.core_ui.foundation.noRippleClickable import com.anytypeio.anytype.core_ui.views.PreviewTitle2Medium import com.anytypeio.anytype.core_ui.widgets.ListWidgetObjectIcon import com.anytypeio.anytype.presentation.home.InteractionMode +import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction -import com.anytypeio.anytype.presentation.widgets.Widget import com.anytypeio.anytype.presentation.widgets.WidgetId import com.anytypeio.anytype.presentation.widgets.WidgetView import com.anytypeio.anytype.presentation.widgets.WidgetView.ListOfObjects.Type import com.anytypeio.anytype.ui.widgets.menu.WidgetLongClickMenu +import com.anytypeio.anytype.ui.widgets.menu.WidgetMenuItem @Composable fun ListWidgetCard( item: WidgetView.ListOfObjects, mode: InteractionMode, onWidgetObjectClicked: (ObjectWrapper.Basic) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, + onWidgetSourceClicked: (WidgetId) -> Unit, onWidgetMenuTriggered: (WidgetId) -> Unit, onDropDownMenuAction: (DropDownMenuAction) -> Unit, onToggleExpandedWidgetState: (WidgetId) -> Unit, onObjectCheckboxClicked: (Id, Boolean) -> Unit, - onCreateElement: (WidgetView) -> Unit = {} + onCreateElement: (WidgetView) -> Unit = {}, + menuItems: List = emptyList(), + isCardMenuExpanded: MutableState = mutableStateOf(false), + modifier: Modifier = Modifier ) { - val isCardMenuExpanded = remember { - mutableStateOf(false) - } - Box( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp) - .alpha(if (isCardMenuExpanded.value) 0.8f else 1f) - .background( - shape = RoundedCornerShape(16.dp), - color = colorResource(id = R.color.dashboard_card_background) - ) - .then( - if (mode is InteractionMode.Edit) - Modifier.noRippleClickable { - isCardMenuExpanded.value = !isCardMenuExpanded.value - } - else - Modifier - ) - ) { + Box(modifier = modifier) { Column( modifier = Modifier .fillMaxWidth() .padding(horizontal = 0.dp, vertical = 6.dp) ) { + val (title, icon ) = getBundleTitleAndIcon(item.type) WidgetHeader( - title = when(item.type) { - Type.Favorites -> stringResource(id = R.string.favorites) - Type.Recent -> stringResource(id = R.string.recent) - Type.RecentLocal -> stringResource(id = R.string.recently_opened) - Type.Bin -> stringResource(R.string.bin) - }, - icon = item.icon, + title = title, + icon = icon, isCardMenuExpanded = isCardMenuExpanded, - onWidgetHeaderClicked = { onWidgetSourceClicked(item.id, item.source) }, + onWidgetHeaderClicked = { onWidgetSourceClicked(item.id) }, onExpandElement = { onToggleExpandedWidgetState(item.id) }, isExpanded = item.isExpanded, isInEditMode = mode is InteractionMode.Edit, @@ -137,13 +114,37 @@ fun ListWidgetCard( } } WidgetLongClickMenu( - widgetView = item, + menuItems = menuItems, isCardMenuExpanded = isCardMenuExpanded, onDropDownMenuAction = onDropDownMenuAction ) } } +@Composable +fun getBundleTitleAndIcon( + type: Type, +): Pair { + return when (type) { + Type.Favorites -> Pair( + stringResource(id = R.string.favorites), + ObjectIcon.SimpleIcon("star", R.color.text_primary) + ) + Type.Recent -> Pair( + stringResource(id = R.string.recent), + ObjectIcon.SimpleIcon("pencil", R.color.text_primary) + ) + Type.RecentLocal -> Pair( + stringResource(id = R.string.recently_opened), + ObjectIcon.SimpleIcon("eye", R.color.text_primary) + ) + Type.Bin -> Pair( + stringResource(R.string.bin), + ObjectIcon.SimpleIcon("calendar", R.color.text_primary) + ) + } +} + @Composable fun CompactListWidgetList( mode: InteractionMode, diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/SpaceChatWidget.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/SpaceChatWidget.kt index 9a843b7bf8..ae762af8e4 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/SpaceChatWidget.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/SpaceChatWidget.kt @@ -147,7 +147,7 @@ fun SpaceChatWidgetCard( Spacer(modifier = Modifier.width(16.dp)) } WidgetLongClickMenu( - widgetView = item, + menuItems = emptyList(), isCardMenuExpanded = isCardMenuExpanded, onDropDownMenuAction = onDropDownMenuAction ) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/TreeWidget.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/TreeWidget.kt index ddc4491ef8..e8e1672a91 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/TreeWidget.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/TreeWidget.kt @@ -1,7 +1,6 @@ package com.anytypeio.anytype.ui.widgets.types import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -10,19 +9,18 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Divider import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.rotate import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.anytypeio.anytype.R @@ -39,6 +37,7 @@ import com.anytypeio.anytype.presentation.widgets.Widget import com.anytypeio.anytype.presentation.widgets.WidgetId import com.anytypeio.anytype.presentation.widgets.WidgetView import com.anytypeio.anytype.ui.widgets.menu.WidgetLongClickMenu +import com.anytypeio.anytype.ui.widgets.menu.WidgetMenuItem @Composable fun TreeWidgetCard( @@ -46,49 +45,29 @@ fun TreeWidgetCard( item: WidgetView.Tree, onExpandElement: (TreePath) -> Unit, onWidgetElementClicked: (ObjectWrapper.Basic) -> Unit, - onWidgetSourceClicked: (WidgetId, Widget.Source) -> Unit, + onWidgetSourceClicked: (WidgetId) -> Unit, onWidgetMenuClicked: (WidgetId) -> Unit, onDropDownMenuAction: (DropDownMenuAction) -> Unit, onToggleExpandedWidgetState: (WidgetId) -> Unit, onObjectCheckboxClicked: (Id, Boolean) -> Unit, - onCreateElement: (WidgetView) -> Unit + onCreateElement: (WidgetView) -> Unit, + menuItems: List = emptyList(), + isCardMenuExpanded: MutableState = mutableStateOf(false), + modifier: Modifier = Modifier ) { - val isCardMenuExpanded = remember { - mutableStateOf(false) - } - val isHeaderMenuExpanded = remember { - mutableStateOf(false) - } - - Box( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp) - .alpha(if (isCardMenuExpanded.value || isHeaderMenuExpanded.value) 0.8f else 1f) - .background( - shape = RoundedCornerShape(16.dp), - color = colorResource(id = R.color.dashboard_card_background) - ) - .then( - if (mode is InteractionMode.Edit) - Modifier.noRippleClickable { - isCardMenuExpanded.value = !isCardMenuExpanded.value - } - else - Modifier - ) - ) { + Box(modifier = modifier) { Column( Modifier.padding( top = 6.dp, bottom = 6.dp, ) ) { + val (title, icon) = getTitleAndIcon(item, item.icon) WidgetHeader( - title = item.getPrettyName(), - icon = item.icon, + title = title, + icon = icon, isCardMenuExpanded = isCardMenuExpanded, - onWidgetHeaderClicked = { onWidgetSourceClicked(item.id, item.source) }, + onWidgetHeaderClicked = { onWidgetSourceClicked(item.id) }, onExpandElement = { onToggleExpandedWidgetState(item.id) }, isExpanded = item.isExpanded, isInEditMode = mode is InteractionMode.Edit, @@ -120,7 +99,7 @@ fun TreeWidgetCard( } } WidgetLongClickMenu( - widgetView = item, + menuItems = menuItems, isCardMenuExpanded = isCardMenuExpanded, onDropDownMenuAction = onDropDownMenuAction ) @@ -232,6 +211,34 @@ private fun TreeWidgetTreeItems( } } +@Composable +private fun getTitleAndIcon( + item: WidgetView.Tree, + icon: ObjectIcon +): Pair { + return when (item.source) { + Widget.Source.Bundled.Favorites -> Pair( + stringResource(id = R.string.favorites), + ObjectIcon.SimpleIcon("star", R.color.text_primary) + ) + Widget.Source.Bundled.Recent -> Pair( + stringResource(id = R.string.recent), + ObjectIcon.SimpleIcon("pencil", R.color.text_primary) + ) + Widget.Source.Bundled.RecentLocal -> Pair( + stringResource(id = R.string.recently_opened), + ObjectIcon.SimpleIcon("eye", R.color.text_primary) + ) + Widget.Source.Bundled.Bin -> Pair( + stringResource(R.string.bin), + ObjectIcon.SimpleIcon("calendar", R.color.text_primary) + ) + else -> Pair( + item.getPrettyName(), + icon + ) + } +} @Immutable diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/WidgetHeader.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/WidgetHeader.kt index 6a2ffbd0d9..7a42554c2a 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/WidgetHeader.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/WidgetHeader.kt @@ -78,32 +78,10 @@ fun WidgetHeader( color = colorResource(id = R.color.text_primary), maxLines = 1, overflow = TextOverflow.Ellipsis, - modifier = Modifier - .weight(1f) - .then( - if (isInEditMode) - Modifier - else if (hasReadOnlyAccess) { - Modifier.noRippleClickable { - onWidgetHeaderClicked() - } - } else - Modifier.combinedClickable( - onClick = onWidgetHeaderClicked, - onLongClick = { - isCardMenuExpanded.value = !isCardMenuExpanded.value - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - if (isCardMenuExpanded.value) { - onWidgetMenuTriggered() - } - }, - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) - ) + modifier = Modifier.weight(1f) ) - if (canCreateObject) { + if (canCreateObject && !hasReadOnlyAccess) { Box( Modifier .size(18.dp) diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt index dfd1b6ec75..3191ea00c1 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt @@ -756,4 +756,9 @@ sealed class Command { val objectId: Id ) : Publishing() } + + data class ObjectTypesSetOrder( + val spaceId: Id, + val orderedIds: List + ) : Command() } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconCompose.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconCompose.kt index 66c56d46ec..6b9a6f495d 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconCompose.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconCompose.kt @@ -25,6 +25,7 @@ import com.anytypeio.anytype.core_ui.widgets.objectIcon.DeletedIconView import com.anytypeio.anytype.core_ui.widgets.objectIcon.EmojiIconView import com.anytypeio.anytype.core_ui.widgets.objectIcon.ImageIconView import com.anytypeio.anytype.core_ui.widgets.objectIcon.ObjectIconProfile +import com.anytypeio.anytype.core_ui.widgets.objectIcon.SimpleIcon import com.anytypeio.anytype.core_ui.widgets.objectIcon.TypeIconView import com.anytypeio.anytype.core_utils.const.MimeTypes import com.anytypeio.anytype.presentation.objects.ObjectIcon @@ -125,6 +126,14 @@ fun ListWidgetObjectIcon( iconSize = iconSize, ) } + + is ObjectIcon.SimpleIcon -> { + SimpleIcon( + modifier = modifier, + icon = icon, + backgroundSize = iconSize + ) + } } } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt index eeae23c20c..430f7abe78 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt @@ -31,6 +31,7 @@ import com.anytypeio.anytype.presentation.objects.ObjectIcon.TypeIcon import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor import coil3.load import coil3.request.CachePolicy +import com.anytypeio.anytype.presentation.objects.ObjectIcon.TypeIcon.* import timber.log.Timber class ObjectIconWidget @JvmOverloads constructor( @@ -153,22 +154,22 @@ class ObjectIconWidget @JvmOverloads constructor( setCheckbox(icon.isChecked) } - is ObjectIcon.TypeIcon.Fallback -> { + is TypeIcon.Fallback -> { setTypeIcon(icon) } - is ObjectIcon.TypeIcon.Default -> { + is TypeIcon.Default -> { setTypeIcon(icon) } - ObjectIcon.TypeIcon.Deleted -> { + TypeIcon.Deleted -> { setDeletedIcon() } - is ObjectIcon.TypeIcon.Emoji -> { + is TypeIcon.Emoji -> { setEmoji( emoji = icon.unicode, - fallback = TypeIcon.Fallback(rawValue = icon.rawValue) + fallback = Fallback(rawValue = icon.rawValue) ) } @@ -176,6 +177,8 @@ class ObjectIconWidget @JvmOverloads constructor( val iconRes = icon.mime.getMimeIcon() setFileIconWithBackground(iconRes) } + + is ObjectIcon.SimpleIcon -> {} } } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/objectIcon/SimpleIcon.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/objectIcon/SimpleIcon.kt new file mode 100644 index 0000000000..4cc63b9118 --- /dev/null +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/objectIcon/SimpleIcon.kt @@ -0,0 +1,26 @@ +package com.anytypeio.anytype.core_ui.widgets.objectIcon + +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.unit.Dp +import com.anytypeio.anytype.core_ui.widgets.objectIcon.custom_icons.CiExtensionPuzzle +import com.anytypeio.anytype.core_ui.widgets.objectIcon.custom_icons.CustomIcons +import com.anytypeio.anytype.presentation.objects.ObjectIcon + +@Composable +fun SimpleIcon( + modifier: Modifier = Modifier, + icon: ObjectIcon.SimpleIcon, + backgroundSize: Dp, +) { + val (imageVector, tint) = CustomIcons.getImageVector(icon.rawValue) to colorResource(id = icon.color) + IconBoxView( + boxModifier = modifier.size(backgroundSize), + imageModifier = Modifier.size(backgroundSize), + imageVector = imageVector ?: CustomIcons.CiExtensionPuzzle, + contentDescription = "Simple icon", + tint = tint + ) +} \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/objectIcon/TypeIconView.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/objectIcon/TypeIconView.kt index a49c8909e7..9ce14dc0ed 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/objectIcon/TypeIconView.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/objectIcon/TypeIconView.kt @@ -109,7 +109,7 @@ fun TypeIconView( * Helper composable to render an icon inside a Box with centered content. */ @Composable -private fun IconBoxView( +fun IconBoxView( boxModifier: Modifier, imageModifier: Modifier, imageVector: ImageVector, diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt index 1df2584fa8..9c7c23b0a0 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt @@ -1209,4 +1209,8 @@ class BlockDataRepository( override suspend fun spaceChangeInvite(command: Command.SpaceChangeInvite) { remote.spaceChangeInvite(command) } + + override suspend fun objectTypesSetOrder(command: Command.ObjectTypesSetOrder): List { + return remote.objectTypesSetOrder(command) + } } diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt index e964dd8488..830380f7e8 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt @@ -462,6 +462,8 @@ interface BlockRemote { suspend fun setVersion(command: Command.VersionHistory.SetVersion) suspend fun diffVersions(command: Command.VersionHistory.DiffVersions): DiffVersionResponse + suspend fun objectTypesSetOrder(command: Command.ObjectTypesSetOrder): List + //region CHATS suspend fun addChatMessage(command: Command.ChatCommand.AddMessage): Pair> diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt index 062806b5e2..c65ca611f5 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt @@ -552,4 +552,6 @@ interface BlockRepository { suspend fun publishingGetList(command: Command.Publishing.GetList): List suspend fun publishingCreate(command: Command.Publishing.Create): String suspend fun publishingRemove(command: Command.Publishing.Remove) + + suspend fun objectTypesSetOrder(command: Command.ObjectTypesSetOrder): List } diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/widgets/UpdateObjectTypesOrderIds.kt b/domain/src/main/java/com/anytypeio/anytype/domain/widgets/UpdateObjectTypesOrderIds.kt new file mode 100644 index 0000000000..630a11c09d --- /dev/null +++ b/domain/src/main/java/com/anytypeio/anytype/domain/widgets/UpdateObjectTypesOrderIds.kt @@ -0,0 +1,28 @@ +package com.anytypeio.anytype.domain.widgets + +import com.anytypeio.anytype.core_models.Command +import com.anytypeio.anytype.core_models.Id +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 UpdateObjectTypesOrderIds @Inject constructor( + private val repository: BlockRepository, + dispatchers: AppCoroutineDispatchers +) : ResultInteractor>(dispatchers.io) { + + override suspend fun doWork(params: Params): List { + val command = Command.ObjectTypesSetOrder( + spaceId = params.spaceId.id, + orderedIds = params.orderedIds + ) + return repository.objectTypesSetOrder(command) + } + + data class Params( + val spaceId: SpaceId, + val orderedIds: List + ) +} \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt index e81267c27e..0b72990f65 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt @@ -1052,6 +1052,10 @@ class BlockMiddleware( return middleware.diffVersions(command) } + override suspend fun objectTypesSetOrder(command: Command.ObjectTypesSetOrder): List { + return middleware.objectTypesSetOrder(command) + } + override suspend fun addChatMessage(command: Command.ChatCommand.AddMessage): Pair> { return middleware.chatAddMessage(command) } diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt index 804efde4fb..51c3aa836c 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt @@ -3218,6 +3218,18 @@ class Middleware @Inject constructor( logResponseIfDebug(response, time) } + @Throws(Exception::class) + fun objectTypesSetOrder(command: Command.ObjectTypesSetOrder): List { + val request = Rpc.ObjectType.SetOrder.Request( + spaceId = command.spaceId, + typeIds = command.orderedIds + ) + logRequestIfDebug(request) + val (response, time) = measureTimedValue { service.objectTypesSetOrder(request) } + logResponseIfDebug(response, time) + return response.orderIds + } + private fun logRequestIfDebug(request: Any) { if (BuildConfig.DEBUG) { logger.logRequest(request).also { diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt index 119fab115d..f4d854b884 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt @@ -480,6 +480,9 @@ interface MiddlewareService { @Throws(Exception::class) fun blockWidgetSetViewId(request: Rpc.BlockWidget.SetViewId.Request) : Rpc.BlockWidget.SetViewId.Response + @Throws(Exception::class) + fun objectTypesSetOrder(request: Rpc.ObjectType.SetOrder.Request) : Rpc.ObjectType.SetOrder.Response + //endregion //region WORKSPACE diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt index f4dd79bcce..691d720bf6 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt @@ -238,6 +238,19 @@ class MiddlewareServiceImplementation @Inject constructor( } } + override fun objectTypesSetOrder(request: Rpc.ObjectType.SetOrder.Request): Rpc.ObjectType.SetOrder.Response { + val encoded = Service.objectTypeSetOrder( + Rpc.ObjectType.SetOrder.Request.ADAPTER.encode(request) + ) + val response = Rpc.ObjectType.SetOrder.Response.ADAPTER.decode(encoded) + val error = response.error + if (error != null && error.code != Rpc.ObjectType.SetOrder.Response.Error.Code.NULL) { + throw Exception(error.description) + } else { + return response + } + } + override fun blockDataViewRelationAdd(request: Rpc.BlockDataview.Relation.Add.Request): Rpc.BlockDataview.Relation.Add.Response { val encoded = Service.blockDataviewRelationAdd( Rpc.BlockDataview.Relation.Add.Request.ADAPTER.encode(request) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/AnalyticsExt.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/AnalyticsExt.kt index e60ce98212..0016c43d85 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/AnalyticsExt.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/AnalyticsExt.kt @@ -1938,7 +1938,7 @@ fun CoroutineScope.sendDeleteWidgetEvent( fun CoroutineScope.sendClickWidgetTitleEvent( analytics: Analytics, bundled: Widget.Source.Bundled, - isAutoCreated: Boolean? + isAutoCreated: Boolean? = null ) { sendEvent( analytics = analytics, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt index 551c143a3b..0544d0253c 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt @@ -90,6 +90,7 @@ import com.anytypeio.anytype.domain.widgets.DeleteWidget import com.anytypeio.anytype.domain.widgets.GetWidgetSession import com.anytypeio.anytype.domain.widgets.SaveWidgetSession import com.anytypeio.anytype.domain.widgets.SetWidgetActiveView +import com.anytypeio.anytype.domain.widgets.UpdateObjectTypesOrderIds import com.anytypeio.anytype.domain.widgets.UpdateWidget import com.anytypeio.anytype.domain.workspace.SpaceManager import com.anytypeio.anytype.presentation.BuildConfig @@ -250,7 +251,8 @@ class HomeScreenViewModel( private val copyInviteLinkToClipboard: CopyInviteLinkToClipboard, private val userSettingsRepository: UserSettingsRepository, private val scope: CoroutineScope, - private val stringResourceProvider : StringResourceProvider + private val stringResourceProvider : StringResourceProvider, + private val updateObjectTypesOrderIds: UpdateObjectTypesOrderIds ) : NavigationViewModel(), Reducer, WidgetActiveViewStateHolder by widgetActiveViewStateHolder, @@ -941,7 +943,32 @@ class HomeScreenViewModel( type: Int, target: Id? ) { - //DROID-3965 legacy logic, adding widgets only through "pin" button + viewModelScope.launch { + val params = CreateWidget.Params( + ctx = ctx, + source = source, + type = when (type) { + Command.ChangeWidgetType.TYPE_LINK -> WidgetLayout.LINK + Command.ChangeWidgetType.TYPE_TREE -> WidgetLayout.TREE + Command.ChangeWidgetType.TYPE_LIST -> WidgetLayout.LIST + Command.ChangeWidgetType.TYPE_VIEW -> WidgetLayout.VIEW + Command.ChangeWidgetType.TYPE_COMPACT_LIST -> WidgetLayout.COMPACT_LIST + else -> WidgetLayout.LINK + }, + target = target, + position = if (!target.isNullOrEmpty()) Position.BOTTOM else Position.NONE + ) + createWidget.async(params).fold( + onFailure = { + sendToast("Error while creating widget: ${it.message}") + Timber.e(it, "Error while creating widget") + }, + onSuccess = { payload -> + Timber.d("Widget created successfully, dispatching payload") + objectPayloadDispatcher.send(payload) + } + ) + } } /** @@ -1142,15 +1169,15 @@ class HomeScreenViewModel( } } - fun onWidgetSourceClicked(widget: Id, source: Widget.Source) { - Timber.d("onWidgetSourceClicked: $source") - val isAutoCreated = widgets.value?.find { it.id == widget }?.isAutoCreated - when (source) { + fun onWidgetSourceClicked(widgetId: Id) { + Timber.d("onWidgetSourceClicked:") + val widget = widgets.value?.find { it.id == widgetId } ?: return + Timber.d("Widget source: ${widget.source}") + when (val source = widget.source) { is Widget.Source.Bundled.Favorites -> { viewModelScope.sendClickWidgetTitleEvent( analytics = analytics, bundled = source, - isAutoCreated = isAutoCreated ) // TODO switch to bundled widgets id viewModelScope.launch { @@ -1165,8 +1192,7 @@ class HomeScreenViewModel( is Widget.Source.Bundled.Recent -> { viewModelScope.sendClickWidgetTitleEvent( analytics = analytics, - bundled = source, - isAutoCreated = isAutoCreated + bundled = source ) // TODO switch to bundled widgets id viewModelScope.launch { @@ -1181,8 +1207,7 @@ class HomeScreenViewModel( is Widget.Source.Bundled.RecentLocal -> { viewModelScope.sendClickWidgetTitleEvent( analytics = analytics, - bundled = source, - isAutoCreated = isAutoCreated + bundled = source ) // TODO switch to bundled widgets id viewModelScope.launch { @@ -1197,7 +1222,7 @@ class HomeScreenViewModel( is Widget.Source.Default -> { if (source.obj.isArchived != true) { dispatchSelectHomeTabCustomSourceEvent( - widget = widget, + widget = widgetId, source = source ) proceedWithOpeningObject(source.obj) @@ -1665,10 +1690,6 @@ class HomeScreenViewModel( mode.value = InteractionMode.Default } - private fun proceedWithEnteringEditMode() { - mode.value = InteractionMode.Edit - } - private fun proceedWithOpeningObject(obj: ObjectWrapper.Basic) { proceedWithNavigation(obj.navigation()) } @@ -2905,7 +2926,8 @@ class HomeScreenViewModel( private val copyInviteLinkToClipboard: CopyInviteLinkToClipboard, private val userRepo: UserSettingsRepository, private val scope: CoroutineScope, - private val stringResourceProvider : StringResourceProvider + private val stringResourceProvider : StringResourceProvider, + private val updateObjectTypesOrderIds: UpdateObjectTypesOrderIds ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T = HomeScreenViewModel( @@ -2966,7 +2988,8 @@ class HomeScreenViewModel( copyInviteLinkToClipboard = copyInviteLinkToClipboard, userSettingsRepository = userRepo, scope = scope, - stringResourceProvider = stringResourceProvider + stringResourceProvider = stringResourceProvider, + updateObjectTypesOrderIds = updateObjectTypesOrderIds ) as T } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectIcon.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectIcon.kt index a89dcf5582..492866af14 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectIcon.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectIcon.kt @@ -108,6 +108,8 @@ sealed class ObjectIcon { } } } + + data class SimpleIcon(val rawValue: String, val color: Int) : ObjectIcon() } sealed class SpaceMemberIconView { diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModelTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModelTest.kt index 927457172e..1437205365 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModelTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModelTest.kt @@ -80,6 +80,7 @@ import com.anytypeio.anytype.domain.widgets.DeleteWidget import com.anytypeio.anytype.domain.widgets.GetWidgetSession import com.anytypeio.anytype.domain.widgets.SaveWidgetSession import com.anytypeio.anytype.domain.widgets.SetWidgetActiveView +import com.anytypeio.anytype.domain.widgets.UpdateObjectTypesOrderIds import com.anytypeio.anytype.domain.widgets.UpdateWidget import com.anytypeio.anytype.domain.workspace.SpaceManager import com.anytypeio.anytype.presentation.MockObjectTypes.objectTypePage @@ -213,6 +214,9 @@ class HomeScreenViewModelTest { @Mock lateinit var storeOfRelations: StoreOfRelations + @Mock + lateinit var updateObjectTypesOrderIds: UpdateObjectTypesOrderIds + @Mock lateinit var objectWatcher: ObjectWatcher @@ -3011,7 +3015,8 @@ class HomeScreenViewModelTest { copyInviteLinkToClipboard = copyInviteLinkToClipboard, userSettingsRepository = userSettingsRepository, scope = GlobalScope, - stringResourceProvider = stringResourceProvider + stringResourceProvider = stringResourceProvider, + updateObjectTypesOrderIds = updateObjectTypesOrderIds ) companion object {