1
0
Fork 0
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:
Mikhail 2022-04-28 11:40:01 +03:00 committed by GitHub
parent 4a7f8df07b
commit a78dc6ffd3
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 127 additions and 0 deletions

View file

@ -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

View file

@ -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,

View file

@ -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)

View 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>

View file

@ -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>

View file

@ -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)
}
}

View file

@ -233,4 +233,6 @@ interface BlockDataStore {
suspend fun setObjectLayout(ctx: Id, layout: ObjectType.Layout) : Payload
suspend fun clearFileCache()
suspend fun duplicateObject(id: Id): Id
}

View file

@ -233,4 +233,6 @@ interface BlockRemote {
suspend fun setObjectLayout(ctx: Id, layout: ObjectType.Layout) : Payload
suspend fun clearFileCache()
suspend fun duplicateObject(id: Id): Id
}

View file

@ -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)

View file

@ -292,4 +292,6 @@ interface BlockRepository {
suspend fun setObjectLayout(ctx: Id, layout: ObjectType.Layout) : Payload
suspend fun clearFileCache()
suspend fun duplicateObject(id: Id): Id
}

View file

@ -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)
}
}

View file

@ -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)
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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
}
}
}

View file

@ -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()
}

View file

@ -329,6 +329,7 @@ class EditorViewModel(
is Action.SetUnsplashImage -> {
proceedWithSettingUnsplashImage(action)
}
is Action.Duplicate -> proceedWithOpeningPage(action.id)
Action.SearchOnPage -> onEnterSearchModeClicked()
Action.UndoRedo -> onUndoRedoActionClicked()
}

View file

@ -9,6 +9,7 @@ enum class ObjectAction {
SEARCH_ON_PAGE,
USE_AS_TEMPLATE,
UNDO_REDO,
DUPLICATE,
LOCK,
UNLOCK
}

View file

@ -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,