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

DROID-1953 Objects. | Enhancement | Creating widgets from object's three-dot menu (#607)

This commit is contained in:
Evgenii Kozlov 2023-11-28 17:08:31 +01:00 committed by GitHub
parent 299cd654a3
commit e9ea4fd74d
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 122 additions and 18 deletions

View file

@ -5,7 +5,6 @@ import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
import com.anytypeio.anytype.core_utils.tools.FeatureToggles
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
@ -15,12 +14,15 @@ import com.anytypeio.anytype.domain.collections.AddObjectToCollection
import com.anytypeio.anytype.domain.dashboard.interactor.AddToFavorite
import com.anytypeio.anytype.domain.dashboard.interactor.RemoveFromFavorite
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
import com.anytypeio.anytype.domain.page.AddBackLinkToObject
import com.anytypeio.anytype.domain.page.CloseBlock
import com.anytypeio.anytype.domain.page.OpenPage
import com.anytypeio.anytype.domain.templates.CreateTemplateFromObject
import com.anytypeio.anytype.domain.widgets.CreateWidget
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.common.Action
import com.anytypeio.anytype.presentation.common.Delegator
import com.anytypeio.anytype.presentation.editor.Editor
@ -120,7 +122,9 @@ object ObjectMenuModule {
addObjectToCollection: AddObjectToCollection,
createTemplateFromObject: CreateTemplateFromObject,
setObjectDetails: SetObjectDetails,
debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader
debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader,
createWidget: CreateWidget,
spaceManager: SpaceManager
): ObjectMenuViewModel.Factory = ObjectMenuViewModel.Factory(
setObjectIsArchived = setObjectIsArchived,
duplicateObject = duplicateObject,
@ -138,7 +142,9 @@ object ObjectMenuModule {
addObjectToCollection = addObjectToCollection,
createTemplateFromObject = createTemplateFromObject,
setObjectDetails = setObjectDetails,
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader,
createWidget = createWidget,
spaceManager = spaceManager
)
@JvmStatic
@ -206,7 +212,9 @@ object ObjectSetMenuModule {
featureToggles: FeatureToggles,
dispatcher: Dispatcher<Payload>,
addObjectToCollection: AddObjectToCollection,
debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader
debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader,
createWidget: CreateWidget,
spaceManager: SpaceManager
): ObjectSetMenuViewModel.Factory = ObjectSetMenuViewModel.Factory(
setObjectIsArchived = setObjectIsArchived,
addToFavorite = addToFavorite,
@ -220,7 +228,9 @@ object ObjectSetMenuModule {
dispatcher = dispatcher,
menuOptionsProvider = createMenuOptionsProvider(state, featureToggles),
addObjectToCollection = addObjectToCollection,
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader,
createWidget = createWidget,
spaceManager = spaceManager
)
@JvmStatic

View file

@ -84,6 +84,10 @@ class ObjectActionAdapter(
ivActionIcon.setImageResource(R.drawable.ic_set_as_default_24)
tvActionTitle.setText(R.string.set_as_default)
}
ObjectAction.CREATE_WIDGET -> {
ivActionIcon.setImageResource(R.drawable.ic_object_action_to_widgets_24)
tvActionTitle.setText(R.string.object_action_to_widgets)
}
else -> {}
}
}

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M4,3.5H20C20.828,3.5 21.5,4.172 21.5,5V8C21.5,8.828 20.828,9.5 20,9.5H4C3.172,9.5 2.5,8.828 2.5,8V5C2.5,4.172 3.172,3.5 4,3.5ZM1,5C1,3.343 2.343,2 4,2H20C21.657,2 23,3.343 23,5V8C23,9.657 21.657,11 20,11H4C2.343,11 1,9.657 1,8V5ZM4,15.5H20C20.828,15.5 21.5,16.172 21.5,17V20C21.5,20.828 20.828,21.5 20,21.5H4C3.172,21.5 2.5,20.828 2.5,20V17C2.5,16.172 3.172,15.5 4,15.5ZM1,17C1,15.343 2.343,14 4,14H20C21.657,14 23,15.343 23,17V20C23,21.657 21.657,23 20,23H4C2.343,23 1,21.657 1,20V17Z"
android:fillColor="@color/glyph_active"
android:fillType="evenOdd"/>
</vector>

View file

@ -445,7 +445,6 @@
<string name="layout_todo_description">Action-focused layout with a checkbox</string>
<string name="move_to_bin">To Bin</string>
<string name="undoredo">Undo/Redo</string>
<string name="object_action_duplicate">Duplicate</string>
<string name="object_removal_process">Object removal process</string>
<string name="please_wait_your_object_deletion">Please wait a bit. Your objects will be deleted shortly.</string>
<string name="large">Large</string>
@ -1087,6 +1086,13 @@
<!--endregion-->
<!--region OBJECT ACTIONS -->
<string name="object_action_duplicate">Duplicate</string>
<string name="object_action_to_widgets">To widgets</string>
<!--endregion-->
<!--region CONTENT DESCRIPTIONS FOR ACCESSIBILITY -->
<string name="content_description_add_block" translatable="false">Add block button</string>

View file

@ -15,5 +15,6 @@ enum class ObjectAction {
UNLOCK,
LINK_TO,
DELETE_FILES,
SET_AS_DEFAULT
SET_AS_DEFAULT,
CREATE_WIDGET
}

View file

@ -24,6 +24,8 @@ import com.anytypeio.anytype.domain.`object`.SetObjectDetails
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
import com.anytypeio.anytype.domain.page.AddBackLinkToObject
import com.anytypeio.anytype.domain.templates.CreateTemplateFromObject
import com.anytypeio.anytype.domain.widgets.CreateWidget
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.common.Action
import com.anytypeio.anytype.presentation.common.Delegator
import com.anytypeio.anytype.presentation.editor.Editor
@ -35,6 +37,7 @@ import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.presentation.util.downloader.DebugGoroutinesShareDownloader
import com.anytypeio.anytype.presentation.util.downloader.DebugTreeShareDownloader
import com.anytypeio.anytype.presentation.util.downloader.MiddlewareShareDownloader
import javax.inject.Inject
import kotlinx.coroutines.launch
import timber.log.Timber
@ -48,6 +51,7 @@ class ObjectMenuViewModel(
dispatcher: Dispatcher<Payload>,
menuOptionsProvider: ObjectMenuOptionsProvider,
duplicateObject: DuplicateObject,
createWidget: CreateWidget,
private val debugTreeShareDownloader: DebugTreeShareDownloader,
private val storage: Editor.Storage,
private val analytics: Analytics,
@ -55,7 +59,8 @@ class ObjectMenuViewModel(
private val addObjectToCollection: AddObjectToCollection,
private val createTemplateFromObject: CreateTemplateFromObject,
private val setObjectDetails: SetObjectDetails,
private val debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader
private val debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader,
private val spaceManager: SpaceManager
) : ObjectMenuViewModelBase(
setObjectIsArchived = setObjectIsArchived,
addToFavorite = addToFavorite,
@ -68,7 +73,9 @@ class ObjectMenuViewModel(
analytics = analytics,
menuOptionsProvider = menuOptionsProvider,
addObjectToCollection = addObjectToCollection,
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader,
createWidget = createWidget,
spaceManager = spaceManager
) {
private val objectRestrictions = storage.objectRestrictions.current()
@ -96,6 +103,8 @@ class ObjectMenuViewModel(
}
}
add(ObjectAction.CREATE_WIDGET)
if (isTemplate) {
add(ObjectAction.SET_AS_DEFAULT)
}
@ -265,6 +274,11 @@ class ObjectMenuViewModel(
ObjectAction.SET_AS_DEFAULT -> {
proceedWithSettingAsDefaultTemplate(ctx = ctx)
}
ObjectAction.CREATE_WIDGET -> {
val details = storage.details.current().details[ctx]
val wrapper = ObjectWrapper.Basic(details?.map ?: emptyMap())
proceedWithCreatingWidget(obj = wrapper)
}
ObjectAction.MOVE_TO,
ObjectAction.MOVE_TO_BIN,
ObjectAction.DELETE_FILES -> {
@ -395,7 +409,7 @@ class ObjectMenuViewModel(
}
@Suppress("UNCHECKED_CAST")
class Factory(
class Factory @Inject constructor(
private val setObjectIsArchived: SetObjectIsArchived,
private val duplicateObject: DuplicateObject,
private val debugTreeShareDownloader: DebugTreeShareDownloader,
@ -412,7 +426,9 @@ class ObjectMenuViewModel(
private val addObjectToCollection: AddObjectToCollection,
private val createTemplateFromObject: CreateTemplateFromObject,
private val setObjectDetails: SetObjectDetails,
private val debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader
private val debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader,
private val createWidget: CreateWidget,
private val spaceManager: SpaceManager
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ObjectMenuViewModel(
@ -432,7 +448,9 @@ class ObjectMenuViewModel(
addObjectToCollection = addObjectToCollection,
createTemplateFromObject = createTemplateFromObject,
setObjectDetails = setObjectDetails,
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader,
createWidget = createWidget,
spaceManager = spaceManager
) as T
}
}

View file

@ -7,15 +7,20 @@ import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.core_models.WidgetLayout
import com.anytypeio.anytype.core_models.isDataView
import com.anytypeio.anytype.domain.base.fold
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
import com.anytypeio.anytype.domain.dashboard.interactor.AddToFavorite
import com.anytypeio.anytype.domain.dashboard.interactor.RemoveFromFavorite
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
import com.anytypeio.anytype.domain.page.AddBackLinkToObject
import com.anytypeio.anytype.domain.widgets.CreateWidget
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.common.Action
import com.anytypeio.anytype.presentation.common.BaseViewModel
import com.anytypeio.anytype.presentation.common.Delegator
@ -50,7 +55,9 @@ abstract class ObjectMenuViewModelBase(
private val menuOptionsProvider: ObjectMenuOptionsProvider,
private val duplicateObject: DuplicateObject,
private val addObjectToCollection: AddObjectToCollection,
private val debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader
private val debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader,
private val createWidget: CreateWidget,
private val spaceManager: SpaceManager
) : BaseViewModel() {
protected val jobs = mutableListOf<Job>()
@ -345,6 +352,36 @@ abstract class ObjectMenuViewModelBase(
}
}
fun proceedWithCreatingWidget(obj: ObjectWrapper.Basic) {
viewModelScope.launch {
val config = spaceManager.getConfig()
if (config != null) {
createWidget(
CreateWidget.Params(
ctx = config.widgets,
source = obj.id,
type = if (obj.layout.isDataView()) {
WidgetLayout.COMPACT_LIST
} else {
WidgetLayout.TREE
}
)
).collect { result ->
result.fold(
onSuccess = {
sendToast("Widget created")
isDismissed.value = true
},
onFailure = {
Timber.e(it, "Error while creating widget")
sendToast(SOMETHING_WENT_WRONG_MSG)
}
)
}
}
}
}
sealed class Command {
object OpenObjectIcons : Command()
object OpenSetIcons : Command()

View file

@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
@ -14,6 +15,8 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
import com.anytypeio.anytype.domain.page.AddBackLinkToObject
import com.anytypeio.anytype.domain.widgets.CreateWidget
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.common.Action
import com.anytypeio.anytype.presentation.common.Delegator
import com.anytypeio.anytype.presentation.objects.ObjectAction
@ -21,6 +24,7 @@ import com.anytypeio.anytype.presentation.sets.dataViewState
import com.anytypeio.anytype.presentation.sets.state.ObjectState
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.presentation.util.downloader.DebugGoroutinesShareDownloader
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
@ -34,6 +38,8 @@ class ObjectSetMenuViewModel(
urlBuilder: UrlBuilder,
dispatcher: Dispatcher<Payload>,
menuOptionsProvider: ObjectMenuOptionsProvider,
createWidget: CreateWidget,
spaceManager: SpaceManager,
private val objectState: StateFlow<ObjectState>,
private val analytics: Analytics,
private val addObjectToCollection: AddObjectToCollection,
@ -50,11 +56,13 @@ class ObjectSetMenuViewModel(
analytics = analytics,
menuOptionsProvider = menuOptionsProvider,
addObjectToCollection = addObjectToCollection,
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader,
createWidget = createWidget,
spaceManager = spaceManager
) {
@Suppress("UNCHECKED_CAST")
class Factory(
class Factory @Inject constructor(
private val setObjectIsArchived: SetObjectIsArchived,
private val addToFavorite: AddToFavorite,
private val removeFromFavorite: RemoveFromFavorite,
@ -67,7 +75,9 @@ class ObjectSetMenuViewModel(
private val objectState: StateFlow<ObjectState>,
private val menuOptionsProvider: ObjectMenuOptionsProvider,
private val addObjectToCollection: AddObjectToCollection,
private val debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader
private val debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader,
private val createWidget: CreateWidget,
private val spaceManager: SpaceManager
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ObjectSetMenuViewModel(
@ -83,7 +93,9 @@ class ObjectSetMenuViewModel(
dispatcher = dispatcher,
menuOptionsProvider = menuOptionsProvider,
addObjectToCollection = addObjectToCollection,
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader,
createWidget = createWidget,
spaceManager = spaceManager
) as T
}
}
@ -148,6 +160,7 @@ class ObjectSetMenuViewModel(
} else {
add(ObjectAction.ADD_TO_FAVOURITE)
}
add(ObjectAction.CREATE_WIDGET)
val dataViewState = objectState.value.dataViewState()
if (dataViewState != null && !dataViewState.objectRestrictions.contains(ObjectRestriction.DUPLICATE)) {
add(ObjectAction.DUPLICATE)
@ -175,6 +188,11 @@ class ObjectSetMenuViewModel(
ObjectAction.DUPLICATE -> {
proceedWithDuplication(ctx = ctx, details = objectState.value.dataViewState()?.details)
}
ObjectAction.CREATE_WIDGET -> {
val details = objectState.value.dataViewState()?.details?.get(ctx)
val wrapper = ObjectWrapper.Basic(details?.map ?: emptyMap())
proceedWithCreatingWidget(obj = wrapper)
}
ObjectAction.MOVE_TO,
ObjectAction.SEARCH_ON_PAGE,
ObjectAction.UNDO_REDO,