mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
Editor | Feature | Duplicate an object (#2195)
Co-authored-by: Mikhail Iudin <mayudin@anytype.io>
This commit is contained in:
parent
4a7f8df07b
commit
a78dc6ffd3
19 changed files with 127 additions and 0 deletions
|
@ -11,6 +11,7 @@ import com.anytypeio.anytype.di.feature.cover.UnsplashSubComponent
|
|||
import com.anytypeio.anytype.di.feature.relations.RelationAddToObjectSubComponent
|
||||
import com.anytypeio.anytype.di.feature.relations.RelationCreateFromScratchForObjectBlockSubComponent
|
||||
import com.anytypeio.anytype.di.feature.relations.RelationCreateFromScratchForObjectSubComponent
|
||||
import com.anytypeio.anytype.domain.`object`.DuplicateObject
|
||||
import com.anytypeio.anytype.domain.`object`.ObjectTypesProvider
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
|
@ -565,6 +566,15 @@ object EditorUseCaseModule {
|
|||
documentEmojiProvider = documentEmojiIconProvider
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDuplicateObject(
|
||||
repo: BlockRepository
|
||||
): DuplicateObject = DuplicateObject(
|
||||
repo = repo
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.anytypeio.anytype.di.feature
|
|||
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.domain.`object`.DuplicateObject
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateFields
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dashboard.interactor.AddToFavorite
|
||||
|
@ -73,6 +74,7 @@ object ObjectMenuModule {
|
|||
@PerDialog
|
||||
fun provideViewModelFactory(
|
||||
setObjectIsArchived: SetObjectIsArchived,
|
||||
duplicateObject: DuplicateObject,
|
||||
addToFavorite: AddToFavorite,
|
||||
removeFromFavorite: RemoveFromFavorite,
|
||||
storage: Editor.Storage,
|
||||
|
@ -82,6 +84,7 @@ object ObjectMenuModule {
|
|||
delegator: Delegator<Action>
|
||||
): ObjectMenuViewModel.Factory = ObjectMenuViewModel.Factory(
|
||||
setObjectIsArchived = setObjectIsArchived,
|
||||
duplicateObject = duplicateObject,
|
||||
addToFavorite = addToFavorite,
|
||||
removeFromFavorite = removeFromFavorite,
|
||||
storage = storage,
|
||||
|
|
|
@ -36,6 +36,10 @@ class ObjectActionAdapter(
|
|||
ivActionIcon.setImageResource(R.drawable.ic_object_action_archive)
|
||||
tvActionTitle.setText(R.string.move_to_bin)
|
||||
}
|
||||
ObjectAction.DUPLICATE -> {
|
||||
ivActionIcon.setImageResource(R.drawable.ic_object_action_duplicate)
|
||||
tvActionTitle.setText(R.string.object_action_duplicate)
|
||||
}
|
||||
ObjectAction.UNDO_REDO -> {
|
||||
ivActionIcon.setImageResource(R.drawable.ic_object_action_undoredo)
|
||||
tvActionTitle.setText(R.string.undoredo)
|
||||
|
|
20
core-ui/src/main/res/drawable/ic_object_action_duplicate.xml
Normal file
20
core-ui/src/main/res/drawable/ic_object_action_duplicate.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<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="M19.5,7.4995H10.5C8.8432,7.4995 7.5,8.8427 7.5,10.4995V19.4995C7.5,21.1564 8.8432,22.4995 10.5,22.4995H19.5C21.1569,22.4995 22.5,21.1564 22.5,19.4995V10.4995C22.5,8.8427 21.1569,7.4995 19.5,7.4995ZM10.5,5.9995C8.0147,5.9995 6,8.0142 6,10.4995V19.4995C6,21.9848 8.0147,23.9995 10.5,23.9995H19.5C21.9853,23.9995 24,21.9848 24,19.4995V10.4995C24,8.0142 21.9853,5.9995 19.5,5.9995H10.5Z"
|
||||
android:fillColor="@color/glyph_active"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M4.5,1.4995H13.5C15.1569,1.4995 16.5,2.8427 16.5,4.4995V5.9995H18V4.4995C18,2.0142 15.9853,-0.0005 13.5,-0.0005H4.5C2.0147,-0.0005 0,2.0142 0,4.4995V13.4995C0,15.9848 2.0147,17.9995 4.5,17.9995H6V16.4995H4.5C2.8431,16.4995 1.5,15.1564 1.5,13.4995V4.4995C1.5,2.8427 2.8431,1.4995 4.5,1.4995Z"
|
||||
android:fillColor="@color/glyph_active"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M15,10.4995L15,10.4995A0.75,0.75 0,0 1,15.75 11.2495L15.75,18.7495A0.75,0.75 0,0 1,15 19.4995L15,19.4995A0.75,0.75 0,0 1,14.25 18.7495L14.25,11.2495A0.75,0.75 0,0 1,15 10.4995z"
|
||||
android:fillColor="@color/glyph_active"/>
|
||||
<path
|
||||
android:pathData="M10.5,14.9995L10.5,14.9995A0.75,0.75 0,0 1,11.25 14.2495L18.75,14.2495A0.75,0.75 0,0 1,19.5 14.9995L19.5,14.9995A0.75,0.75 0,0 1,18.75 15.7495L11.25,15.7495A0.75,0.75 0,0 1,10.5 14.9995z"
|
||||
android:fillColor="@color/glyph_active"/>
|
||||
</vector>
|
|
@ -468,6 +468,7 @@
|
|||
<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="settings">Settings</string>
|
||||
|
|
|
@ -578,4 +578,8 @@ class BlockDataRepository(
|
|||
factory.remote.setObjectLayout(ctx, layout)
|
||||
|
||||
override suspend fun clearFileCache() = factory.remote.clearFileCache()
|
||||
|
||||
override suspend fun duplicateObject(id: Id): Id {
|
||||
return factory.remote.duplicateObject(id)
|
||||
}
|
||||
}
|
|
@ -233,4 +233,6 @@ interface BlockDataStore {
|
|||
suspend fun setObjectLayout(ctx: Id, layout: ObjectType.Layout) : Payload
|
||||
|
||||
suspend fun clearFileCache()
|
||||
|
||||
suspend fun duplicateObject(id: Id): Id
|
||||
}
|
|
@ -233,4 +233,6 @@ interface BlockRemote {
|
|||
suspend fun setObjectLayout(ctx: Id, layout: ObjectType.Layout) : Payload
|
||||
|
||||
suspend fun clearFileCache()
|
||||
|
||||
suspend fun duplicateObject(id: Id): Id
|
||||
}
|
|
@ -105,6 +105,8 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore {
|
|||
command: Command.Duplicate
|
||||
): Pair<List<Id>, Payload> = remote.duplicate(command)
|
||||
|
||||
override suspend fun duplicateObject(id: Id) = remote.duplicateObject(id)
|
||||
|
||||
override suspend fun unlink(
|
||||
command: Command.Unlink
|
||||
): Payload = remote.unlink(command)
|
||||
|
|
|
@ -292,4 +292,6 @@ interface BlockRepository {
|
|||
suspend fun setObjectLayout(ctx: Id, layout: ObjectType.Layout) : Payload
|
||||
|
||||
suspend fun clearFileCache()
|
||||
|
||||
suspend fun duplicateObject(id: Id): Id
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.anytypeio.anytype.domain.`object`
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
||||
class DuplicateObject(
|
||||
private val repo: BlockRepository
|
||||
) : BaseUseCase<Id, Id>() {
|
||||
|
||||
override suspend fun run(params: Id) = safe {
|
||||
repo.duplicateObject(params)
|
||||
}
|
||||
}
|
|
@ -122,6 +122,8 @@ class BlockMiddleware(
|
|||
command: Command.Duplicate
|
||||
): Pair<List<Id>, Payload> = middleware.duplicate(command)
|
||||
|
||||
override suspend fun duplicateObject(id: Id) = middleware.objectDuplicate(id)
|
||||
|
||||
override suspend fun move(command: Command.Move): Payload {
|
||||
return middleware.move(command)
|
||||
}
|
||||
|
|
|
@ -1689,4 +1689,18 @@ class Middleware(
|
|||
val response = service.fileListOffload(request)
|
||||
if (BuildConfig.DEBUG) logResponse(response)
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun objectDuplicate(id: Id): Id {
|
||||
|
||||
val request = Rpc.ObjectDuplicate.Request(contextId = id)
|
||||
|
||||
if (BuildConfig.DEBUG) logRequest(request)
|
||||
|
||||
val response = service.objectDuplicate(request)
|
||||
|
||||
if (BuildConfig.DEBUG) logResponse(response)
|
||||
|
||||
return response.id
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.anytypeio.anytype.middleware.service
|
||||
|
||||
import anytype.Rpc.ObjectDuplicate
|
||||
import anytype.Rpc.Account
|
||||
import anytype.Rpc.Block
|
||||
import anytype.Rpc.BlockList
|
||||
|
@ -255,4 +256,7 @@ interface MiddlewareService {
|
|||
|
||||
@Throws(Exception::class)
|
||||
fun unsplashDownload(request: UnsplashDownload.Request) : UnsplashDownload.Response
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun objectDuplicate(request: ObjectDuplicate.Request) : ObjectDuplicate.Response
|
||||
}
|
|
@ -9,6 +9,7 @@ import anytype.Rpc.ExportLocalstore
|
|||
import anytype.Rpc.FileList
|
||||
import anytype.Rpc.Navigation
|
||||
import anytype.Rpc.Object
|
||||
import anytype.Rpc.ObjectDuplicate
|
||||
import anytype.Rpc.ObjectList
|
||||
import anytype.Rpc.ObjectType
|
||||
import anytype.Rpc.Page
|
||||
|
@ -997,4 +998,17 @@ class MiddlewareServiceImplementation : MiddlewareService {
|
|||
return response
|
||||
}
|
||||
}
|
||||
|
||||
override fun objectDuplicate(request: ObjectDuplicate.Request): ObjectDuplicate.Response {
|
||||
val encoded = Service.objectDuplicate(
|
||||
ObjectDuplicate.Request.ADAPTER.encode(request)
|
||||
)
|
||||
val response = ObjectDuplicate.Response.ADAPTER.decode(encoded)
|
||||
val error = response.error
|
||||
if (error != null && error.code != ObjectDuplicate.Response.Error.Code.NULL) {
|
||||
throw Exception(error.description)
|
||||
} else {
|
||||
return response
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,4 +21,5 @@ sealed class Action {
|
|||
data class SetUnsplashImage(val img: Id) : Action()
|
||||
object SearchOnPage: Action()
|
||||
object UndoRedo : Action()
|
||||
data class Duplicate(val id: Id) : Action()
|
||||
}
|
|
@ -329,6 +329,7 @@ class EditorViewModel(
|
|||
is Action.SetUnsplashImage -> {
|
||||
proceedWithSettingUnsplashImage(action)
|
||||
}
|
||||
is Action.Duplicate -> proceedWithOpeningPage(action.id)
|
||||
Action.SearchOnPage -> onEnterSearchModeClicked()
|
||||
Action.UndoRedo -> onUndoRedoActionClicked()
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ enum class ObjectAction {
|
|||
SEARCH_ON_PAGE,
|
||||
USE_AS_TEMPLATE,
|
||||
UNDO_REDO,
|
||||
DUPLICATE,
|
||||
LOCK,
|
||||
UNLOCK
|
||||
}
|
|
@ -11,6 +11,7 @@ import com.anytypeio.anytype.core_models.Block
|
|||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
|
||||
import com.anytypeio.anytype.domain.`object`.DuplicateObject
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateFields
|
||||
import com.anytypeio.anytype.domain.dashboard.interactor.AddToFavorite
|
||||
import com.anytypeio.anytype.domain.dashboard.interactor.RemoveFromFavorite
|
||||
|
@ -164,6 +165,7 @@ class ObjectMenuViewModel(
|
|||
addToFavorite: AddToFavorite,
|
||||
removeFromFavorite: RemoveFromFavorite,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
private val duplicateObject: DuplicateObject,
|
||||
private val storage: Editor.Storage,
|
||||
private val analytics: Analytics,
|
||||
private val updateFields: UpdateFields,
|
||||
|
@ -208,6 +210,10 @@ class ObjectMenuViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
if (!isProfile) {
|
||||
add(ObjectAction.DUPLICATE)
|
||||
}
|
||||
|
||||
add(ObjectAction.USE_AS_TEMPLATE)
|
||||
}
|
||||
|
||||
|
@ -284,6 +290,9 @@ class ObjectMenuViewModel(
|
|||
ObjectAction.DELETE -> {
|
||||
proceedWithUpdatingArchivedStatus(ctx = ctx, isArchived = true)
|
||||
}
|
||||
ObjectAction.DUPLICATE -> {
|
||||
proceedWithDuplication(ctx = ctx)
|
||||
}
|
||||
ObjectAction.RESTORE -> {
|
||||
proceedWithUpdatingArchivedStatus(ctx = ctx, isArchived = false)
|
||||
}
|
||||
|
@ -317,6 +326,21 @@ class ObjectMenuViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceedWithDuplication(ctx: Id) {
|
||||
viewModelScope.launch {
|
||||
duplicateObject(ctx).process(
|
||||
failure = {
|
||||
Timber.e(it, "Duplication error")
|
||||
_toasts.emit(SOMETHING_WENT_WRONG_MSG)
|
||||
},
|
||||
success = {
|
||||
_toasts.emit("Your object is duplicated")
|
||||
delegator.delegate(Action.Duplicate(it))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithUpdatingLockStatus(
|
||||
ctx: Id,
|
||||
isLocked: Boolean
|
||||
|
@ -374,6 +398,7 @@ class ObjectMenuViewModel(
|
|||
@Suppress("UNCHECKED_CAST")
|
||||
class Factory(
|
||||
private val setObjectIsArchived: SetObjectIsArchived,
|
||||
private val duplicateObject: DuplicateObject,
|
||||
private val addToFavorite: AddToFavorite,
|
||||
private val removeFromFavorite: RemoveFromFavorite,
|
||||
private val storage: Editor.Storage,
|
||||
|
@ -385,6 +410,7 @@ class ObjectMenuViewModel(
|
|||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ObjectMenuViewModel(
|
||||
setObjectIsArchived = setObjectIsArchived,
|
||||
duplicateObject = duplicateObject,
|
||||
addToFavorite = addToFavorite,
|
||||
removeFromFavorite = removeFromFavorite,
|
||||
storage = storage,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue