mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-1095 Widgets | Enhancement | Add-below actions for widgets (#3030)
This commit is contained in:
parent
315c4bcd20
commit
56243a870e
17 changed files with 152 additions and 39 deletions
|
@ -15,7 +15,6 @@ import androidx.fragment.app.viewModels
|
|||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
|
@ -64,9 +63,7 @@ class HomeScreenFragment : BaseComposeFragment() {
|
|||
widgets = vm.views.collectAsState().value,
|
||||
mode = vm.mode.collectAsState().value,
|
||||
onExpand = { path -> vm.onExpand(path) },
|
||||
onCreateWidget = {
|
||||
findNavController().navigate(R.id.selectWidgetSourceScreen)
|
||||
},
|
||||
onCreateWidget = vm::onCreateWidgetClicked,
|
||||
onEditWidgets = vm::onEditWidgets,
|
||||
onExitEditMode = vm::onExitEditMode,
|
||||
onWidgetMenuAction = { widget: Id, action: DropDownMenuAction ->
|
||||
|
@ -136,7 +133,8 @@ class HomeScreenFragment : BaseComposeFragment() {
|
|||
}
|
||||
is Command.SelectWidgetSource -> {
|
||||
findNavController().navigate(
|
||||
R.id.selectWidgetSourceScreen
|
||||
R.id.selectWidgetSourceScreen,
|
||||
args = SelectWidgetSourceFragment.args(command.target)
|
||||
)
|
||||
}
|
||||
is Command.ChangeWidgetType -> {
|
||||
|
@ -157,7 +155,8 @@ class HomeScreenFragment : BaseComposeFragment() {
|
|||
args = SelectWidgetTypeFragment.args(
|
||||
ctx = command.ctx,
|
||||
source = command.source,
|
||||
layout = command.layout
|
||||
layout = command.layout,
|
||||
target = command.target
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
|
||||
private val ctx: Id get() = arg(CTX_KEY)
|
||||
private val widget: Id get() = arg(WIDGET_ID_KEY)
|
||||
private val target: Id? get() = argOrNull(TARGET_KEY)
|
||||
private val source: Id get() = arg(WIDGET_SOURCE_KEY)
|
||||
private val type: Int get() = arg(WIDGET_TYPE_KEY)
|
||||
private val forExistingWidget: Boolean? get() = argOrNull(FLOW_EXISTING_WIDGET)
|
||||
|
@ -103,7 +104,7 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
type = type
|
||||
)
|
||||
} else {
|
||||
vm.onStartWithNewWidget()
|
||||
vm.onStartWithNewWidget(target = target)
|
||||
}
|
||||
with(lifecycleScope) {
|
||||
jobs += subscribe(vm.isDismissed) { isDismissed ->
|
||||
|
@ -241,6 +242,7 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
private const val WIDGET_ID_KEY = "arg.select-widget-source.widget-id"
|
||||
private const val WIDGET_TYPE_KEY = "arg.select-widget-source.widget-type"
|
||||
private const val WIDGET_SOURCE_KEY = "arg.select-widget-source.widget-source"
|
||||
private const val TARGET_KEY = "arg.select-widget-source.target"
|
||||
fun args(
|
||||
ctx: Id,
|
||||
widget: Id,
|
||||
|
@ -251,7 +253,15 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
WIDGET_ID_KEY to widget,
|
||||
WIDGET_SOURCE_KEY to source,
|
||||
WIDGET_TYPE_KEY to type,
|
||||
TARGET_KEY to null,
|
||||
FLOW_EXISTING_WIDGET to true
|
||||
)
|
||||
|
||||
/**
|
||||
* Flow for selecting source for new widget.
|
||||
*/
|
||||
fun args(
|
||||
target: Id?
|
||||
) = bundleOf(TARGET_KEY to target)
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_utils.ext.arg
|
||||
import com.anytypeio.anytype.core_utils.ext.argOrNull
|
||||
import com.anytypeio.anytype.core_utils.ext.argString
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
|
@ -31,6 +32,7 @@ class SelectWidgetTypeFragment : BaseBottomSheetComposeFragment() {
|
|||
private val source: Id get() = argString(WIDGET_SOURCE_KEY)
|
||||
private val currentType: Int get() = arg(WIDGET_TYPE_KEY)
|
||||
private val sourceLayout: Int get() = arg(WIDGET_SOURCE_LAYOUT)
|
||||
private val target: Id? get() = argOrNull(TARGET_KEY)
|
||||
private val forExistingWidget: Boolean get() = arg(IS_FOR_EXISTING_WIDGET)
|
||||
|
||||
private val vm by viewModels<SelectWidgetTypeViewModel> { factory }
|
||||
|
@ -58,9 +60,9 @@ class SelectWidgetTypeFragment : BaseBottomSheetComposeFragment() {
|
|||
)
|
||||
} else {
|
||||
vm.onWidgetTypeClicked(
|
||||
ctx = ctx,
|
||||
source = source,
|
||||
view = view
|
||||
view = view,
|
||||
target = target
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +113,7 @@ class SelectWidgetTypeFragment : BaseBottomSheetComposeFragment() {
|
|||
private const val WIDGET_SOURCE_KEY = "arg.select-widget-type.widget-source"
|
||||
private const val WIDGET_SOURCE_LAYOUT = "arg.select-widget-type.widget-source-layout"
|
||||
private const val IS_FOR_EXISTING_WIDGET = "arg.select-widget-type.for-existing-widget"
|
||||
private const val TARGET_KEY = "arg.select-widget-type.target"
|
||||
|
||||
fun args(
|
||||
ctx: Id,
|
||||
|
@ -125,17 +128,20 @@ class SelectWidgetTypeFragment : BaseBottomSheetComposeFragment() {
|
|||
WIDGET_TYPE_KEY to type,
|
||||
IS_FOR_EXISTING_WIDGET to true,
|
||||
WIDGET_SOURCE_LAYOUT to layout,
|
||||
TARGET_KEY to null
|
||||
)
|
||||
|
||||
fun args(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
layout: Int
|
||||
layout: Int,
|
||||
target: Id?
|
||||
) = bundleOf(
|
||||
CTX_KEY to ctx,
|
||||
WIDGET_SOURCE_KEY to source,
|
||||
WIDGET_SOURCE_LAYOUT to layout,
|
||||
IS_FOR_EXISTING_WIDGET to false
|
||||
IS_FOR_EXISTING_WIDGET to false,
|
||||
TARGET_KEY to target
|
||||
)
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ fun WidgetMenu(
|
|||
canChangeType: Boolean = true,
|
||||
canEmptyBin: Boolean = false,
|
||||
canEditWidgets: Boolean = true,
|
||||
canAddBelow: Boolean = true,
|
||||
isExpanded: MutableState<Boolean>,
|
||||
onDropDownMenuAction: (DropDownMenuAction) -> Unit
|
||||
) {
|
||||
|
@ -43,6 +44,24 @@ fun WidgetMenu(
|
|||
color = colorResource(id = R.color.text_primary),
|
||||
fontSize = 17.sp
|
||||
)
|
||||
if (canAddBelow) {
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onDropDownMenuAction(DropDownMenuAction.AddBelow).also {
|
||||
isExpanded.value = false
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.block_action_add_below),
|
||||
style = defaultTextStyle
|
||||
)
|
||||
}
|
||||
Divider(
|
||||
thickness = 0.5.dp,
|
||||
color = colorResource(id = R.color.shape_primary)
|
||||
)
|
||||
}
|
||||
if (canChangeSource) {
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
|
|
|
@ -734,11 +734,15 @@ class BlockDataRepository(
|
|||
override suspend fun createWidget(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
layout: WidgetLayout
|
||||
layout: WidgetLayout,
|
||||
target: Id?,
|
||||
position: Position
|
||||
): Payload = remote.createWidget(
|
||||
ctx = ctx,
|
||||
source = source,
|
||||
layout = layout
|
||||
layout = layout,
|
||||
target = target,
|
||||
position = position
|
||||
)
|
||||
|
||||
override suspend fun updateWidget(
|
||||
|
|
|
@ -325,7 +325,13 @@ interface BlockDataStore {
|
|||
command: Command.CreateBlockLinkWithObject
|
||||
): CreateBlockLinkWithObjectResult
|
||||
|
||||
suspend fun createWidget(ctx: Id, source: Id, layout: WidgetLayout): Payload
|
||||
suspend fun createWidget(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
layout: WidgetLayout,
|
||||
target: Id?,
|
||||
position: Position
|
||||
): Payload
|
||||
|
||||
suspend fun updateWidget(
|
||||
ctx: Id,
|
||||
|
|
|
@ -319,7 +319,13 @@ interface BlockRemote {
|
|||
|
||||
suspend fun createObject(command: Command.CreateObject): CreateObjectResult
|
||||
|
||||
suspend fun createWidget(ctx: Id, source: Id, layout: WidgetLayout): Payload
|
||||
suspend fun createWidget(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
layout: WidgetLayout,
|
||||
target: Id?,
|
||||
position: Position
|
||||
): Payload
|
||||
|
||||
suspend fun updateWidget(
|
||||
ctx: Id,
|
||||
|
|
|
@ -664,11 +664,15 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore {
|
|||
override suspend fun createWidget(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
layout: WidgetLayout
|
||||
layout: WidgetLayout,
|
||||
target: Id?,
|
||||
position: Position
|
||||
): Payload = remote.createWidget(
|
||||
ctx = ctx,
|
||||
source = source,
|
||||
layout = layout
|
||||
layout = layout,
|
||||
target = target,
|
||||
position = position
|
||||
)
|
||||
|
||||
override suspend fun updateWidget(
|
||||
|
|
|
@ -371,7 +371,9 @@ interface BlockRepository {
|
|||
suspend fun createWidget(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
layout: WidgetLayout
|
||||
layout: WidgetLayout,
|
||||
target: Id? = null,
|
||||
position: Position = Position.NONE
|
||||
): Payload
|
||||
|
||||
suspend fun updateWidget(
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.anytypeio.anytype.domain.widgets
|
|||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.Position
|
||||
import com.anytypeio.anytype.core_models.WidgetLayout
|
||||
import com.anytypeio.anytype.domain.base.ResultatInteractor
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
@ -14,12 +15,16 @@ class CreateWidget @Inject constructor(
|
|||
override suspend fun execute(params: Params): Payload = repo.createWidget(
|
||||
ctx = params.ctx,
|
||||
source = params.source,
|
||||
layout = params.type
|
||||
layout = params.type,
|
||||
target = params.target,
|
||||
position = params.position
|
||||
)
|
||||
|
||||
data class Params(
|
||||
val ctx: Id,
|
||||
val source: Id,
|
||||
val type: WidgetLayout
|
||||
val type: WidgetLayout,
|
||||
val target: Id? = null,
|
||||
val position: Position = Position.NONE
|
||||
)
|
||||
}
|
|
@ -701,11 +701,15 @@ class BlockMiddleware(
|
|||
override suspend fun createWidget(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
layout: WidgetLayout
|
||||
layout: WidgetLayout,
|
||||
target: Id?,
|
||||
position: Position
|
||||
): Payload = middleware.createWidgetBlock(
|
||||
ctx = ctx,
|
||||
source = source,
|
||||
layout = layout
|
||||
layout = layout,
|
||||
target = target,
|
||||
position = position
|
||||
)
|
||||
|
||||
override suspend fun updateWidget(
|
||||
|
|
|
@ -1905,7 +1905,9 @@ class Middleware(
|
|||
fun createWidgetBlock(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
layout: WidgetLayout
|
||||
layout: WidgetLayout,
|
||||
target: Id?,
|
||||
position: Position
|
||||
): Payload {
|
||||
val request = Rpc.Block.CreateWidget.Request(
|
||||
contextId = ctx,
|
||||
|
@ -1914,7 +1916,9 @@ class Middleware(
|
|||
link = Block.Content.Link(
|
||||
targetBlockId = source
|
||||
)
|
||||
)
|
||||
),
|
||||
targetId = target.orEmpty(),
|
||||
position = position.toMiddlewareModel()
|
||||
)
|
||||
if (BuildConfig.DEBUG) logRequest(request)
|
||||
val response = service.blockCreateWidget(request)
|
||||
|
|
|
@ -293,7 +293,8 @@ class HomeScreenViewModel(
|
|||
Command.SelectWidgetType(
|
||||
ctx = configStorage.get().widgets,
|
||||
source = dispatch.source,
|
||||
layout = dispatch.sourceLayout
|
||||
layout = dispatch.sourceLayout,
|
||||
target = dispatch.target
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -302,7 +303,8 @@ class HomeScreenViewModel(
|
|||
Command.SelectWidgetType(
|
||||
ctx = configStorage.get().widgets,
|
||||
source = dispatch.source,
|
||||
layout = ObjectType.Layout.SET.code
|
||||
layout = ObjectType.Layout.SET.code,
|
||||
target = dispatch.target
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -316,7 +318,8 @@ class HomeScreenViewModel(
|
|||
is WidgetDispatchEvent.TypePicked -> {
|
||||
proceedWithCreatingWidget(
|
||||
source = dispatch.source,
|
||||
type = dispatch.widgetType
|
||||
type = dispatch.widgetType,
|
||||
target = dispatch.target
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +327,11 @@ class HomeScreenViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceedWithCreatingWidget(source: Id, type: Int) {
|
||||
private fun proceedWithCreatingWidget(
|
||||
source: Id,
|
||||
type: Int,
|
||||
target: Id?
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val config = configStorage.get()
|
||||
createWidget(
|
||||
|
@ -336,7 +343,9 @@ class HomeScreenViewModel(
|
|||
Command.ChangeWidgetType.TYPE_TREE -> WidgetLayout.TREE
|
||||
Command.ChangeWidgetType.TYPE_LIST -> WidgetLayout.LIST
|
||||
else -> WidgetLayout.LINK
|
||||
}
|
||||
},
|
||||
target = target,
|
||||
position = if (!target.isNullOrEmpty()) Position.BOTTOM else Position.NONE
|
||||
)
|
||||
).flowOn(appCoroutineDispatchers.io).collect { status ->
|
||||
Timber.d("Status while creating widget: $status")
|
||||
|
@ -452,6 +461,12 @@ class HomeScreenViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onCreateWidgetClicked() {
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.SelectWidgetSource())
|
||||
}
|
||||
}
|
||||
|
||||
fun onEditWidgets() {
|
||||
mode.value = InteractionMode.Edit
|
||||
}
|
||||
|
@ -518,6 +533,9 @@ class HomeScreenViewModel(
|
|||
DropDownMenuAction.EmptyBin -> {
|
||||
proceedWithEmptyingBin()
|
||||
}
|
||||
DropDownMenuAction.AddBelow -> {
|
||||
proceedWithAddingWidgetBelow(widget)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -538,6 +556,12 @@ class HomeScreenViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceedWithAddingWidgetBelow(widget: Id) {
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.SelectWidgetSource(target = widget))
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithChangingType(widget: Id) {
|
||||
Timber.d("onChangeWidgetSourceClicked, widget:[$widget]")
|
||||
val curr = widgets.value.find { it.id == widget }
|
||||
|
@ -804,10 +828,16 @@ sealed class InteractionMode {
|
|||
}
|
||||
|
||||
sealed class Command {
|
||||
object SelectWidgetSource : Command()
|
||||
|
||||
/**
|
||||
* [target] optional target, below which new widget will be created
|
||||
*/
|
||||
data class SelectWidgetSource(val target: Id? = null) : Command()
|
||||
|
||||
data class SelectWidgetType(
|
||||
val ctx: Id,
|
||||
val source: Id,
|
||||
val target: Id?,
|
||||
val layout: Int
|
||||
) : Command()
|
||||
|
||||
|
|
|
@ -90,9 +90,9 @@ class SelectWidgetSourceViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
fun onStartWithNewWidget() {
|
||||
fun onStartWithNewWidget(target: Id?) {
|
||||
Timber.d("onStart with picking source for new widget")
|
||||
config = Config.NewWidget
|
||||
config = Config.NewWidget(target)
|
||||
proceedWithSearchQuery()
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,10 @@ class SelectWidgetSourceViewModel(
|
|||
is Config.NewWidget -> {
|
||||
viewModelScope.launch {
|
||||
dispatcher.send(
|
||||
WidgetDispatchEvent.SourcePicked.Bundled(source = view.id)
|
||||
WidgetDispatchEvent.SourcePicked.Bundled(
|
||||
source = view.id,
|
||||
target = curr.target
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +157,8 @@ class SelectWidgetSourceViewModel(
|
|||
dispatcher.send(
|
||||
WidgetDispatchEvent.SourcePicked.Default(
|
||||
source = view.id,
|
||||
sourceLayout = view.layout?.code ?: -1
|
||||
sourceLayout = view.layout?.code ?: -1,
|
||||
target = curr.target
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -202,7 +206,7 @@ class SelectWidgetSourceViewModel(
|
|||
|
||||
sealed class Config {
|
||||
object None: Config()
|
||||
object NewWidget : Config()
|
||||
data class NewWidget(val target: Id?) : Config()
|
||||
data class ExistingWidget(
|
||||
val ctx: Id,
|
||||
val widget: Id,
|
||||
|
|
|
@ -112,8 +112,8 @@ class SelectWidgetTypeViewModel(
|
|||
}
|
||||
|
||||
fun onWidgetTypeClicked(
|
||||
ctx: Id,
|
||||
source: Id,
|
||||
target: Id?,
|
||||
view: WidgetTypeView
|
||||
) {
|
||||
if (!view.isSelected) {
|
||||
|
@ -121,6 +121,7 @@ class SelectWidgetTypeViewModel(
|
|||
widgetDispatcher.send(
|
||||
WidgetDispatchEvent.TypePicked(
|
||||
source = source,
|
||||
target = target,
|
||||
widgetType = when (view) {
|
||||
is WidgetTypeView.Link -> Command.ChangeWidgetType.TYPE_LINK
|
||||
is WidgetTypeView.Tree -> Command.ChangeWidgetType.TYPE_TREE
|
||||
|
|
|
@ -4,14 +4,22 @@ import com.anytypeio.anytype.core_models.Id
|
|||
|
||||
sealed class WidgetDispatchEvent {
|
||||
sealed class SourcePicked : WidgetDispatchEvent() {
|
||||
data class Default(val source: Id, val sourceLayout: Int) : SourcePicked()
|
||||
data class Default(
|
||||
val source: Id,
|
||||
val sourceLayout: Int,
|
||||
val target: Id?
|
||||
) : SourcePicked()
|
||||
|
||||
/**
|
||||
* [source] bundled source - one of [BundledWidgetSourceIds]
|
||||
*/
|
||||
data class Bundled(val source: Id) : SourcePicked()
|
||||
data class Bundled(val source: Id, val target: Id?) : SourcePicked()
|
||||
}
|
||||
data class TypePicked(val source: Id, val widgetType: Int) : WidgetDispatchEvent()
|
||||
data class TypePicked(
|
||||
val source: Id,
|
||||
val target: Id?,
|
||||
val widgetType: Int
|
||||
) : WidgetDispatchEvent()
|
||||
data class SourceChanged(
|
||||
val ctx: Id,
|
||||
val widget: Id,
|
||||
|
|
|
@ -93,6 +93,7 @@ sealed class DropDownMenuAction {
|
|||
object ChangeWidgetType : DropDownMenuAction()
|
||||
object ChangeWidgetSource : DropDownMenuAction()
|
||||
object RemoveWidget : DropDownMenuAction()
|
||||
object AddBelow: DropDownMenuAction()
|
||||
object EditWidgets : DropDownMenuAction()
|
||||
object EmptyBin: DropDownMenuAction()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue