mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3538 Widgets | Enhancement | Add plus button to system and object-type widgets (#2260)
This commit is contained in:
parent
d635e34465
commit
c51a302051
10 changed files with 146 additions and 22 deletions
|
@ -99,7 +99,8 @@ fun HomeScreen(
|
|||
onSpaceWidgetShareIconClicked: (ObjectWrapper.SpaceView) -> Unit,
|
||||
onSeeAllObjectsClicked: (WidgetView.Gallery) -> Unit,
|
||||
onCreateObjectInsideWidget: (Id) -> Unit,
|
||||
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit
|
||||
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit,
|
||||
onCreateElement: (WidgetView) -> Unit = {}
|
||||
) {
|
||||
|
||||
Box(modifier = modifier.fillMaxSize()) {
|
||||
|
@ -121,7 +122,8 @@ fun HomeScreen(
|
|||
onSeeAllObjectsClicked = onSeeAllObjectsClicked,
|
||||
onCreateWidget = onCreateWidget,
|
||||
onCreateObjectInsideWidget = onCreateObjectInsideWidget,
|
||||
onCreateDataViewObject = onCreateDataViewObject
|
||||
onCreateDataViewObject = onCreateDataViewObject,
|
||||
onCreateElement = onCreateElement
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = mode is InteractionMode.Edit,
|
||||
|
@ -192,7 +194,8 @@ private fun WidgetList(
|
|||
onSeeAllObjectsClicked: (WidgetView.Gallery) -> Unit,
|
||||
onCreateWidget: () -> Unit,
|
||||
onCreateObjectInsideWidget: (Id) -> Unit,
|
||||
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit
|
||||
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit,
|
||||
onCreateElement: (WidgetView) -> Unit = {}
|
||||
) {
|
||||
val views = remember { mutableStateOf(widgets) }
|
||||
views.value = widgets
|
||||
|
@ -315,7 +318,8 @@ private fun WidgetList(
|
|||
onChangeWidgetView = onChangeWidgetView,
|
||||
onToggleExpandedWidgetState = onToggleExpandedWidgetState,
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked,
|
||||
onCreateDataViewObject = onCreateDataViewObject
|
||||
onCreateDataViewObject = onCreateDataViewObject,
|
||||
onCreateElement = onCreateElement
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -331,7 +335,8 @@ private fun WidgetList(
|
|||
onChangeWidgetView = onChangeWidgetView,
|
||||
onToggleExpandedWidgetState = onToggleExpandedWidgetState,
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked,
|
||||
onCreateDataViewObject = onCreateDataViewObject
|
||||
onCreateDataViewObject = onCreateDataViewObject,
|
||||
onCreateElement = onCreateElement
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -389,7 +394,8 @@ private fun WidgetList(
|
|||
onWidgetSourceClicked = onWidgetSourceClicked,
|
||||
onWidgetMenuAction = onWidgetMenuAction,
|
||||
onToggleExpandedWidgetState = onToggleExpandedWidgetState,
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked,
|
||||
onCreateElement = onCreateElement
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -403,7 +409,8 @@ private fun WidgetList(
|
|||
onWidgetSourceClicked = onWidgetSourceClicked,
|
||||
onWidgetMenuAction = onWidgetMenuAction,
|
||||
onToggleExpandedWidgetState = onToggleExpandedWidgetState,
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked,
|
||||
onCreateElement = onCreateElement
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -521,7 +528,8 @@ private fun ListOfObjectsItem(
|
|||
onWidgetSourceClicked: (Widget.Source) -> Unit,
|
||||
onWidgetMenuAction: (WidgetId, DropDownMenuAction) -> Unit,
|
||||
onToggleExpandedWidgetState: (WidgetId) -> Unit,
|
||||
onObjectCheckboxClicked: (Id, Boolean) -> Unit
|
||||
onObjectCheckboxClicked: (Id, Boolean) -> Unit,
|
||||
onCreateElement: (WidgetView) -> Unit = {}
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -545,7 +553,8 @@ private fun ListOfObjectsItem(
|
|||
onWidgetMenuAction(item.id, action)
|
||||
},
|
||||
onToggleExpandedWidgetState = onToggleExpandedWidgetState,
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked,
|
||||
onCreateElement = onCreateElement
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = mode is InteractionMode.Edit,
|
||||
|
@ -584,7 +593,8 @@ private fun SetOfObjectsItem(
|
|||
onChangeWidgetView: (WidgetId, ViewId) -> Unit,
|
||||
onToggleExpandedWidgetState: (WidgetId) -> Unit,
|
||||
onObjectCheckboxClicked: (Id, Boolean) -> Unit,
|
||||
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit
|
||||
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit,
|
||||
onCreateElement: (WidgetView) -> Unit = {}
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -610,7 +620,8 @@ private fun SetOfObjectsItem(
|
|||
onToggleExpandedWidgetState = onToggleExpandedWidgetState,
|
||||
mode = mode,
|
||||
onObjectCheckboxClicked = onObjectCheckboxClicked,
|
||||
onCreateDataViewObject = onCreateDataViewObject
|
||||
onCreateDataViewObject = onCreateDataViewObject,
|
||||
onCreateElement = onCreateElement
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = mode is InteractionMode.Edit,
|
||||
|
|
|
@ -210,6 +210,7 @@ class HomeScreenFragment : BaseComposeFragment(),
|
|||
onNavBarShareButtonClicked = vm::onNavBarShareIconClicked,
|
||||
navPanelState = vm.navPanelState.collectAsStateWithLifecycle().value,
|
||||
onHomeButtonClicked = vm::onHomeButtonClicked,
|
||||
onCreateElement = vm::onCreateWidgetElementClicked
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,8 @@ fun DataViewListWidgetCard(
|
|||
onChangeWidgetView: (WidgetId, ViewId) -> Unit,
|
||||
onToggleExpandedWidgetState: (WidgetId) -> Unit,
|
||||
onObjectCheckboxClicked: (Id, Boolean) -> Unit,
|
||||
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit
|
||||
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit,
|
||||
onCreateElement: (WidgetView) -> Unit = {}
|
||||
) {
|
||||
val isCardMenuExpanded = remember {
|
||||
mutableStateOf(false)
|
||||
|
@ -115,7 +116,9 @@ fun DataViewListWidgetCard(
|
|||
isExpanded = item.isExpanded,
|
||||
isInEditMode = mode is InteractionMode.Edit,
|
||||
hasReadOnlyAccess = mode is InteractionMode.ReadOnly,
|
||||
onDropDownMenuAction = onDropDownMenuAction
|
||||
onDropDownMenuAction = onDropDownMenuAction,
|
||||
canCreate = mode is InteractionMode.Default,
|
||||
onCreateElement = { onCreateElement(item) }
|
||||
)
|
||||
if (item.tabs.size > 1 && item.isExpanded) {
|
||||
DataViewTabs(
|
||||
|
|
|
@ -44,7 +44,8 @@ fun ListWidgetCard(
|
|||
onWidgetSourceClicked: (Widget.Source) -> Unit,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> Unit,
|
||||
onToggleExpandedWidgetState: (WidgetId) -> Unit,
|
||||
onObjectCheckboxClicked: (Id, Boolean) -> Unit
|
||||
onObjectCheckboxClicked: (Id, Boolean) -> Unit,
|
||||
onCreateElement: (WidgetView) -> Unit = {}
|
||||
) {
|
||||
val isCardMenuExpanded = remember {
|
||||
mutableStateOf(false)
|
||||
|
@ -89,7 +90,9 @@ fun ListWidgetCard(
|
|||
isExpanded = item.isExpanded,
|
||||
isInEditMode = mode is InteractionMode.Edit,
|
||||
hasReadOnlyAccess = mode is InteractionMode.ReadOnly,
|
||||
onDropDownMenuAction = onDropDownMenuAction
|
||||
onDropDownMenuAction = onDropDownMenuAction,
|
||||
canCreate = (item.type is Type.Favorites && mode is InteractionMode.Default),
|
||||
onCreateElement = { onCreateElement(item) }
|
||||
)
|
||||
if (item.elements.isNotEmpty()) {
|
||||
if (item.isCompact) {
|
||||
|
|
|
@ -10,16 +10,19 @@ import androidx.compose.animation.fadeOut
|
|||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
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.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.Text
|
||||
|
@ -32,6 +35,7 @@ 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.draw.rotate
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
|
@ -254,9 +258,11 @@ fun WidgetHeader(
|
|||
onWidgetHeaderClicked: () -> Unit,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> Unit,
|
||||
onExpandElement: () -> Unit = {},
|
||||
onCreateElement: () -> Unit = {},
|
||||
isExpanded: Boolean = false,
|
||||
isInEditMode: Boolean = true,
|
||||
hasReadOnlyAccess: Boolean = false
|
||||
hasReadOnlyAccess: Boolean = false,
|
||||
canCreate: Boolean = false
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
Box(
|
||||
|
@ -297,6 +303,25 @@ fun WidgetHeader(
|
|||
)
|
||||
)
|
||||
|
||||
if (canCreate) {
|
||||
Box(
|
||||
Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(end = 42.dp)
|
||||
.fillMaxHeight()
|
||||
.width(34.dp)
|
||||
.noRippleClickable {
|
||||
onCreateElement()
|
||||
}
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_widget_system_plus_18),
|
||||
contentDescription = stringResource(R.string.content_description_plus_button),
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
WidgetArrow(
|
||||
modifier = Modifier.align(Alignment.CenterEnd),
|
||||
isInEditMode = isInEditMode,
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
android:pathData="M7.5,15L12.5,10L7.5,5"
|
||||
android:strokeWidth="1.5"
|
||||
android:fillColor="@color/transparent"
|
||||
android:strokeColor="@color/text_primary"
|
||||
android:strokeColor="@color/glyph_active"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
|
10
core-ui/src/main/res/drawable/ic_widget_system_plus_18.xml
Normal file
10
core-ui/src/main/res/drawable/ic_widget_system_plus_18.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:pathData="M8.25,15.25C8.25,15.664 8.586,16 9,16C9.414,16 9.75,15.664 9.75,15.25V9.75H15.25C15.664,9.75 16,9.414 16,9C16,8.586 15.664,8.25 15.25,8.25H9.75V2.75C9.75,2.336 9.414,2 9,2C8.586,2 8.25,2.336 8.25,2.75V8.25H2.75C2.336,8.25 2,8.586 2,9C2,9.414 2.336,9.75 2.75,9.75H8.25V15.25Z"
|
||||
android:fillColor="@color/glyph_active"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -4,8 +4,9 @@ import com.anytypeio.anytype.core_models.Id
|
|||
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 SetObjectListIsFavorite(
|
||||
class SetObjectListIsFavorite @Inject constructor(
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<SetObjectListIsFavorite.Params, Unit>(dispatchers.io) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.anytypeio.anytype.core_models.DVFilterCondition
|
|||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.ObjectTypeIds
|
||||
import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys
|
||||
import com.anytypeio.anytype.core_models.ObjectView
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
|
@ -47,6 +48,7 @@ import com.anytypeio.anytype.domain.bin.EmptyBin
|
|||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.Move
|
||||
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
|
||||
import com.anytypeio.anytype.domain.dashboard.interactor.SetObjectListIsFavorite
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewObject
|
||||
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
|
||||
import com.anytypeio.anytype.domain.launch.GetDefaultObjectType
|
||||
|
@ -226,7 +228,8 @@ class HomeScreenViewModel(
|
|||
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
|
||||
private val getSpaceInviteLink: GetSpaceInviteLink,
|
||||
private val deleteSpace: DeleteSpace,
|
||||
private val spaceMembers: ActiveSpaceMemberSubscriptionContainer
|
||||
private val spaceMembers: ActiveSpaceMemberSubscriptionContainer,
|
||||
private val setAsFavourite: SetObjectListIsFavorite
|
||||
) : NavigationViewModel<HomeScreenViewModel.Navigation>(),
|
||||
Reducer<ObjectView, Payload>,
|
||||
WidgetActiveViewStateHolder by widgetActiveViewStateHolder,
|
||||
|
@ -2347,6 +2350,66 @@ class HomeScreenViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onCreateWidgetElementClicked(view: WidgetView) {
|
||||
viewModelScope.launch {
|
||||
|
||||
}
|
||||
when(view) {
|
||||
is WidgetView.ListOfObjects -> {
|
||||
if (view.type == WidgetView.ListOfObjects.Type.Favorites) {
|
||||
viewModelScope.launch {
|
||||
val space = SpaceId(spaceManager.get())
|
||||
val type = getDefaultObjectType.async(space)
|
||||
.getOrNull()
|
||||
?.type ?: TypeKey(ObjectTypeIds.PAGE)
|
||||
createObject.async(
|
||||
params = CreateObject.Param(
|
||||
space = SpaceId(spaceManager.get()),
|
||||
type = type,
|
||||
prefilled = mapOf(Relations.IS_FAVORITE to true)
|
||||
)
|
||||
).onSuccess { result ->
|
||||
proceedWithNavigation(result.obj.navigation())
|
||||
setAsFavourite.async(
|
||||
params = SetObjectListIsFavorite.Params(
|
||||
objectIds = listOf(result.obj.id),
|
||||
isFavorite = true
|
||||
)
|
||||
)
|
||||
}.onFailure {
|
||||
Timber.e(it, "Error while creating object")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is WidgetView.SetOfObjects -> {
|
||||
viewModelScope.launch {
|
||||
val source = view.source
|
||||
if (source is Widget.Source.Default) {
|
||||
if (source.obj.layout == ObjectType.Layout.OBJECT_TYPE) {
|
||||
val wrapper = ObjectWrapper.Type(source.obj.map)
|
||||
createObject.async(
|
||||
params = CreateObject.Param(
|
||||
space = SpaceId(spaceManager.get()),
|
||||
type = TypeKey(wrapper.uniqueKey),
|
||||
prefilled = mapOf(Relations.IS_FAVORITE to true)
|
||||
)
|
||||
).onSuccess { result ->
|
||||
proceedWithNavigation(result.obj.navigation())
|
||||
}
|
||||
} else {
|
||||
Timber.w("Unexpected source layout: ${source.obj.layout}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else -> {
|
||||
Timber.w("Unexpected widget type: ${view::class.java.simpleName}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Navigation {
|
||||
data class OpenObject(val ctx: Id, val space: Id) : Navigation()
|
||||
data class OpenChat(val ctx: Id, val space: Id) : Navigation()
|
||||
|
@ -2426,7 +2489,8 @@ class HomeScreenViewModel(
|
|||
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
|
||||
private val getSpaceInviteLink: GetSpaceInviteLink,
|
||||
private val deleteSpace: DeleteSpace,
|
||||
private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer
|
||||
private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer,
|
||||
private val setObjectListIsFavorite: SetObjectListIsFavorite
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = HomeScreenViewModel(
|
||||
|
@ -2483,7 +2547,8 @@ class HomeScreenViewModel(
|
|||
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer,
|
||||
getSpaceInviteLink = getSpaceInviteLink,
|
||||
deleteSpace = this@Factory.deleteSpace,
|
||||
spaceMembers = activeSpaceMemberSubscriptionContainer
|
||||
spaceMembers = activeSpaceMemberSubscriptionContainer,
|
||||
setAsFavourite = setObjectListIsFavorite
|
||||
) as T
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import com.anytypeio.anytype.domain.block.interactor.Move
|
|||
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
|
||||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dashboard.interactor.SetObjectListIsFavorite
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewObject
|
||||
import com.anytypeio.anytype.domain.debugging.Logger
|
||||
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
|
||||
|
@ -280,6 +281,9 @@ class HomeScreenViewModelTest {
|
|||
@Mock
|
||||
lateinit var deleteSpace: DeleteSpace
|
||||
|
||||
@Mock
|
||||
lateinit var setObjectListIsFavorite: SetObjectListIsFavorite
|
||||
|
||||
lateinit var userPermissionProvider: UserPermissionProvider
|
||||
|
||||
private val objectPayloadDispatcher = Dispatcher.Default<Payload>()
|
||||
|
@ -2925,7 +2929,8 @@ class HomeScreenViewModelTest {
|
|||
getSpaceInviteLink = getSpaceInviteLink,
|
||||
spaceMembers = activeSpaceMemberSubscriptionContainer,
|
||||
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer,
|
||||
deleteSpace = deleteSpace
|
||||
deleteSpace = deleteSpace,
|
||||
setAsFavourite = setObjectListIsFavorite
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue