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

DROID-786 Sets or Collections | Enhancement | Allow changing view order and bulk deletion of data view's views (#36)

This commit is contained in:
Evgenii Kozlov 2023-06-07 21:36:17 +02:00 committed by GitHub
parent a739f101c6
commit ff65e22d6b
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 326 additions and 101 deletions

View file

@ -3,6 +3,10 @@ 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.PerModal
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer
import com.anytypeio.anytype.domain.dataview.interactor.SetDataViewViewerPosition
import com.anytypeio.anytype.presentation.sets.ManageViewerViewModel
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
import com.anytypeio.anytype.presentation.sets.state.ObjectState
@ -27,6 +31,7 @@ interface ManageViewerSubComponent {
@Module
object ManageViewerModule {
@JvmStatic
@Provides
@PerModal
@ -34,11 +39,33 @@ object ManageViewerModule {
state: MutableStateFlow<ObjectState>,
session: ObjectSetSession,
dispatcher: Dispatcher<Payload>,
analytics: Analytics
analytics: Analytics,
deleteDataViewViewer: DeleteDataViewViewer,
setDataViewViewerPosition: SetDataViewViewerPosition
): ManageViewerViewModel.Factory = ManageViewerViewModel.Factory(
objectState = state,
session = session,
dispatcher = dispatcher,
analytics = analytics
analytics = analytics,
deleteDataViewViewer = deleteDataViewViewer,
setDataViewViewerPosition = setDataViewViewerPosition
)
@JvmStatic
@Provides
@PerModal
fun provideDeleteDataViewViewerUseCase(
repo: BlockRepository
): DeleteDataViewViewer = DeleteDataViewViewer(repo = repo)
@JvmStatic
@Provides
@PerModal
fun provideSetDataViewViewerPosition(
repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
): SetDataViewViewerPosition = SetDataViewViewerPosition(
repo = repo,
dispatchers = dispatchers
)
}

View file

@ -7,13 +7,11 @@ import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.InputType
import android.text.TextUtils
import android.view.GestureDetector
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
import android.view.inputmethod.EditorInfo.IME_ACTION_GO
import android.widget.FrameLayout
@ -810,7 +808,7 @@ open class ObjectSetFragment :
fr.showChildFragment(EMPTY_TAG)
}
is ObjectSetCommand.Modal.ManageViewer -> {
val fr = ManageViewerFragment.new(ctx = command.ctx, dataview = command.dataview)
val fr = ManageViewerFragment.new(ctx = command.ctx, dv = command.dataview)
fr.showChildFragment(EMPTY_TAG)
}
is ObjectSetCommand.Modal.OpenSettings -> {

View file

@ -37,12 +37,19 @@ class ManageViewerFragment : BaseBottomSheetFragment<FragmentManageViewerBinding
private val manageViewerEditAdapter by lazy {
ManageViewerEditAdapter(
onDragListener = this,
onButtonMoreClicked = { vm.onViewerActionClicked(it) }
onButtonMoreClicked = vm::onViewerActionClicked,
onDeleteView = {
vm.onDeleteView(
ctx = ctx,
dv = dv,
view = it
)
}
)
}
private val ctx: String get() = arg(CTX_KEY)
private val dataview: String get() = arg(DATA_VIEW_KEY)
private val ctx: Id get() = arg(CTX_KEY)
private val dv: Id get() = arg(DATA_VIEW_KEY)
@Inject
lateinit var factory: ManageViewerViewModel.Factory
@ -53,7 +60,14 @@ class ManageViewerFragment : BaseBottomSheetFragment<FragmentManageViewerBinding
private val dndBehavior by lazy {
DefaultDragAndDropBehavior(
onItemMoved = { from, to -> manageViewerEditAdapter.onItemMove(from, to) },
onItemDropped = { vm.onOrderChanged(ctx, manageViewerEditAdapter.order) }
onItemDropped = { newPosition ->
vm.onOrderChanged(
ctx = ctx,
dv = dv,
newOrder = manageViewerEditAdapter.order,
newPosition = newPosition
)
}
)
}
@ -89,8 +103,7 @@ class ManageViewerFragment : BaseBottomSheetFragment<FragmentManageViewerBinding
btnAddNewViewer.invisible()
dataViewViewerRecycler.apply {
adapter = manageViewerEditAdapter
//ToDo temporary blocked, because of missing middleware command
//dndItemTouchHelper.attachToRecyclerView(this)
dndItemTouchHelper.attachToRecyclerView(this)
}
}
@ -100,8 +113,7 @@ class ManageViewerFragment : BaseBottomSheetFragment<FragmentManageViewerBinding
btnAddNewViewer.visible()
dataViewViewerRecycler.apply {
adapter = manageViewerAdapter
//ToDo temporary blocked, because of missing middleware command
//dndItemTouchHelper.attachToRecyclerView(null)
dndItemTouchHelper.attachToRecyclerView(null)
}
}
}
@ -122,7 +134,7 @@ class ManageViewerFragment : BaseBottomSheetFragment<FragmentManageViewerBinding
ManageViewerViewModel.Command.OpenCreateScreen -> {
val dialog = CreateDataViewViewerFragment.new(
ctx = ctx,
target = dataview
target = dv
)
dialog.show(parentFragmentManager, null)
}
@ -145,8 +157,8 @@ class ManageViewerFragment : BaseBottomSheetFragment<FragmentManageViewerBinding
)
companion object {
fun new(ctx: Id, dataview: Id): ManageViewerFragment = ManageViewerFragment().apply {
arguments = bundleOf(CTX_KEY to ctx, DATA_VIEW_KEY to dataview)
fun new(ctx: Id, dv: Id): ManageViewerFragment = ManageViewerFragment().apply {
arguments = bundleOf(CTX_KEY to ctx, DATA_VIEW_KEY to dv)
}
const val CTX_KEY = "arg.manage-data-view-viewer.ctx"

View file

@ -59,8 +59,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:paddingBottom="8dp"
tools:listitem="@layout/item_dv_manage_viewer" />

View file

@ -240,6 +240,12 @@ sealed class Event {
val viewer: String
) : DataView()
data class OrderViews(
override val context: String,
val dv: Id,
val order: List<Id>
) : DataView()
data class SetTargetObjectId(
override val context: String,
val dv: String,

View file

@ -2,7 +2,9 @@ package com.anytypeio.anytype.core_ui.features.sets
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.common.AbstractAdapter
import com.anytypeio.anytype.core_ui.common.AbstractViewHolder
@ -19,7 +21,8 @@ import com.anytypeio.anytype.presentation.sets.ManageViewerViewModel.ViewerView
class ManageViewerEditAdapter(
private val onDragListener: OnStartDragListener,
private val onButtonMoreClicked: (ViewerView) -> Unit
private val onButtonMoreClicked: (ViewerView) -> Unit,
private val onDeleteView: (ViewerView) -> Unit
) : AbstractAdapter<ViewerView>(emptyList()), SupportDragAndDropBehavior {
val order: List<String> get() = items.map { it.id }
@ -35,17 +38,21 @@ class ManageViewerEditAdapter(
false
)
).apply {
//ToDo temporary blocked, because of missing middleware command
// itemView.dndDragger.setOnTouchListener { _, event ->
// if (event.action == MotionEvent.ACTION_DOWN) onDragListener.onStartDrag(this)
// false
// }
binding.dndDragger.setOnClickListener {
itemView.context.toast("Coming soon...")
binding.dndDragger.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) onDragListener.onStartDrag(this)
false
}
binding.icRemove.setOnClickListener {
val pos = bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
onDeleteView(items[pos])
}
}
binding.btnActionMore.setOnClickListener {
onButtonMoreClicked(items[bindingAdapterPosition])
val pos = bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
onButtonMoreClicked(items[pos])
}
}
}

View file

@ -18,7 +18,7 @@ import timber.log.Timber
open class DefaultDragAndDropBehavior(
private val onItemMoved: (Int, Int) -> Boolean,
private val onItemDropped: (Int) -> Unit
) : ItemTouchHelper.Callback() {
) : Callback() {
override fun isLongPressDragEnabled() = true

View file

@ -5,6 +5,6 @@
android:viewportHeight="24">
<path
android:pathData="M15.0303,7.0909L5.8655,16.2558L5.0012,20.0187L8.7409,19.1377L17.909,9.9696L15.0303,7.0909ZM18.9697,8.9089L16.091,6.0303L18.1464,3.9748C18.3417,3.7796 18.6583,3.7796 18.8536,3.9748L21.0251,6.1464C21.2204,6.3417 21.2204,6.6582 21.0251,6.8535L18.9697,8.9089ZM9.5,20.4999L3,22.0312L4.5,15.4999L17.0858,2.9141C17.8668,2.1331 19.1332,2.1331 19.9142,2.9142L22.0858,5.0857C22.8668,5.8668 22.8668,7.1331 22.0858,7.9142L9.5,20.4999Z"
android:fillColor="#ACA996"
android:fillColor="@color/glyph_active"
android:fillType="evenOdd"/>
</vector>

View file

@ -4,12 +4,12 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ACA996"
android:fillColor="@color/text_tertiary"
android:pathData="M0,5.5h24v1h-24z" />
<path
android:fillColor="#ACA996"
android:fillColor="@color/text_tertiary"
android:pathData="M0,11.5h24v1h-24z" />
<path
android:fillColor="#ACA996"
android:fillColor="@color/text_tertiary"
android:pathData="M0,17.5h24v1h-24z" />
</vector>

View file

@ -5,7 +5,7 @@
android:viewportHeight="24">
<path
android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:fillColor="#F55522"/>
android:fillColor="@color/palette_system_red"/>
<path
android:pathData="M6,12C6,11.5858 6.3358,11.25 6.75,11.25H17.25C17.6642,11.25 18,11.5858 18,12C18,12.4142 17.6642,12.75 17.25,12.75H6.75C6.3358,12.75 6,12.4142 6,12Z"
android:fillColor="#ffffff"/>

View file

@ -5,10 +5,21 @@
android:layout_height="52dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/icRemove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="20dp"
android:paddingTop="14dp"
android:paddingEnd="@dimen/dp_16"
android:paddingBottom="14dp"
android:src="@drawable/ic_remove_red"
tools:visibility="visible" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="20dp"
android:layout_weight="1"
android:gravity="center_vertical">
@ -33,7 +44,7 @@
android:contentDescription="@string/content_description_more_button"
android:paddingStart="14dp"
android:paddingTop="14dp"
android:paddingEnd="28dp"
android:paddingEnd="18dp"
android:paddingBottom="14dp"
android:src="@drawable/ic_data_view_edit_view"
android:visibility="visible"
@ -49,7 +60,6 @@
android:paddingEnd="@dimen/dp_20"
android:paddingBottom="14dp"
android:src="@drawable/ic_dv_manage_view_dnd_dragger"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>

View file

@ -542,6 +542,18 @@ class BlockDataRepository(
return remote.clearBlockContent(ctx, blockIds)
}
override suspend fun setDataViewViewerPosition(
ctx: Id,
dv: Id,
view: Id,
pos: Int
): Payload = remote.setDataViewViewerPosition(
ctx = ctx,
dv = dv,
view = view,
pos = pos
)
override suspend fun blockDataViewSetSource(
ctx: Id,
block: Id,

View file

@ -95,6 +95,13 @@ interface BlockDataStore {
limit: Int
): Payload
suspend fun setDataViewViewerPosition(
ctx: Id,
dv: Id,
view: Id,
pos: Int
): Payload
suspend fun addRelationToDataView(ctx: Id, dv: Id, relation: Id): Payload
suspend fun deleteRelationFromDataView(ctx: Id, dv: Id, relation: Id): Payload

View file

@ -98,6 +98,13 @@ interface BlockRemote {
limit: Int
): Payload
suspend fun setDataViewViewerPosition(
ctx: Id,
dv: Id,
view: Id,
pos: Int
): Payload
suspend fun addRelationToDataView(ctx: Id, dv: Id, relation: Id): Payload
suspend fun deleteRelationFromDataView(ctx: Id, dv: Id, relation: Id): Payload

View file

@ -223,6 +223,18 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore {
limit = limit
)
override suspend fun setDataViewViewerPosition(
ctx: Id,
dv: Id,
view: Id,
pos: Int
): Payload = remote.setDataViewViewerPosition(
ctx = ctx,
dv = dv,
view = view,
pos = pos
)
override suspend fun addRelationToDataView(
ctx: Id,
dv: Id,

View file

@ -274,6 +274,13 @@ interface BlockRepository {
suspend fun objectToSet(ctx: Id, source: List<String>)
suspend fun objectToCollection(ctx: Id)
suspend fun setDataViewViewerPosition(
ctx: Id,
dv: Id,
view: Id,
pos: Int
): Payload
suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List<String>): Payload
suspend fun createRelation(

View file

@ -0,0 +1,36 @@
package com.anytypeio.anytype.domain.dataview.interactor
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
/**
* Use-case for ordering views of the data view.
*/
class SetDataViewViewerPosition(
private val repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
) : ResultInteractor<SetDataViewViewerPosition.Params, Payload>(dispatchers.io) {
override suspend fun doWork(params: Params): Payload = repo.setDataViewViewerPosition(
ctx = params.ctx,
view = params.viewer,
dv = params.dv,
pos = params.pos
)
/**
* @property [ctx] set or collection id
* @property [dv] data view block id
* @property [viewer] view id, whose position is changed
* @property [pos] new position of the [viewer]
*/
data class Params(
val ctx: Id,
val dv: Id,
val viewer: Id,
val pos: Int
)
}

View file

@ -246,6 +246,18 @@ class BlockMiddleware(
limit = limit
)
override suspend fun setDataViewViewerPosition(
ctx: Id,
dv: Id,
view: Id,
pos: Int
): Payload = middleware.blockDataViewViewSetPosition(
ctx = ctx,
dv = dv,
view = view,
pos = pos
)
override suspend fun addRelationToDataView(
ctx: Id,
dv: Id,

View file

@ -220,6 +220,25 @@ class Middleware(
return response.event.toPayload()
}
@Throws(Exception::class)
fun blockDataViewViewSetPosition(
ctx: Id,
dv: Id,
view: Id,
pos: Int
): Payload {
val request = Rpc.BlockDataview.View.SetPosition.Request(
contextId = ctx,
blockId = dv,
viewId = view,
position = pos
)
if (BuildConfig.DEBUG) logRequest(request)
val response = service.blockDataViewViewSetPosition(request)
if (BuildConfig.DEBUG) logResponse(response)
return response.event.toPayload()
}
@Throws(Exception::class)
fun blockDataViewRelationAdd(
ctx: Id,

View file

@ -32,6 +32,7 @@ class MiddlewareEventChannel(
msg.blockDataviewRelationSet,
msg.blockDataviewRelationDelete,
msg.blockDataviewViewDelete,
msg.blockDataviewViewOrder,
msg.blockDataviewViewSet,
msg.objectRelationsAmend,
msg.objectRelationsRemove,

View file

@ -188,6 +188,15 @@ fun anytype.Event.Message.toCoreModels(
viewer = event.viewId
)
}
blockDataviewViewOrder != null -> {
val event = blockDataviewViewOrder
checkNotNull(event)
Event.Command.DataView.OrderViews(
context = context,
dv = event.id,
order = event.viewIds
)
}
blockDataviewTargetObjectIdSet != null -> {
val event = blockDataviewTargetObjectIdSet
checkNotNull(event)

View file

@ -283,21 +283,15 @@ interface MiddlewareService {
@Throws(Exception::class)
fun blockDataViewViewDelete(request: Rpc.BlockDataview.View.Delete.Request): Rpc.BlockDataview.View.Delete.Response
// @Throws(Exception::class)
// fun blockDataViewRecordCreate(request: Rpc.BlockDataviewRecord.Create.Request): Rpc.BlockDataviewRecord.Create.Response
//
// @Throws(Exception::class)
// fun blockDataViewRecordUpdate(request: Rpc.BlockDataviewRecord.Update.Request): Rpc.BlockDataviewRecord.Update.Response
//
// @Throws(Exception::class)
// fun blockDataViewRecordRelationOptionAdd(request: Rpc.BlockDataviewRecord.RelationOption.Add.Request): Rpc.BlockDataviewRecord.RelationOption.Add.Response
@Throws(Exception::class)
fun blockDataViewRelationAdd(request: Rpc.BlockDataview.Relation.Add.Request): Rpc.BlockDataview.Relation.Add.Response
@Throws(Exception::class)
fun blockDataViewRelationDelete(request: Rpc.BlockDataview.Relation.Delete.Request): Rpc.BlockDataview.Relation.Delete.Response
@Throws(Exception::class)
fun blockDataViewViewSetPosition(request: Rpc.BlockDataview.View.SetPosition.Request): Rpc.BlockDataview.View.SetPosition.Response
@Throws(Exception::class)
fun blockDataViewSetSource(request: Rpc.BlockDataview.SetSource.Request): Rpc.BlockDataview.SetSource.Response

View file

@ -8,7 +8,6 @@ import com.anytypeio.anytype.core_utils.tools.FeatureToggles
import com.anytypeio.anytype.data.auth.exception.BackwardCompatilityNotSupportedException
import com.anytypeio.anytype.data.auth.exception.NotFoundObjectException
import com.anytypeio.anytype.data.auth.exception.UndoRedoExhaustedException
import com.anytypeio.anytype.middleware.BuildConfig
import javax.inject.Inject
import service.Service
@ -22,13 +21,6 @@ class MiddlewareServiceImplementation @Inject constructor(
}
}
init {
// Comment these lines if you want to have more verbose go logs.
if (BuildConfig.DEBUG) {
Service.setEnv("ANYTYPE_LOG_LEVEL", "*=fatal;anytype*=error")
}
}
override fun accountCreate(request: Rpc.Account.Create.Request): Rpc.Account.Create.Response {
val encoded = Service.accountCreate(Rpc.Account.Create.Request.ADAPTER.encode(request))
val response = Rpc.Account.Create.Response.ADAPTER.decode(encoded)
@ -181,48 +173,6 @@ class MiddlewareServiceImplementation @Inject constructor(
}
}
//todo relations refactoring
// override fun blockDataViewRecordCreate(request: Rpc.BlockDataviewRecord.Create.Request): Rpc.BlockDataviewRecord.Create.Response {
// val encoded = Service.blockDataviewRecordCreate(
// Rpc.BlockDataviewRecord.Create.Request.ADAPTER.encode(request)
// )
// val response = Rpc.BlockDataviewRecord.Create.Response.ADAPTER.decode(encoded)
// val error = response.error
// if (error != null && error.code != Rpc.BlockDataviewRecord.Create.Response.Error.Code.NULL) {
// throw Exception(error.description)
// } else {
// return response
// }
// }
//
// override fun blockDataViewRecordRelationOptionAdd(
// request: Rpc.BlockDataviewRecord.RelationOption.Add.Request
// ): Rpc.BlockDataviewRecord.RelationOption.Add.Response {
// val encoded = Service.blockDataviewRecordRelationOptionAdd(
// Rpc.BlockDataviewRecord.RelationOption.Add.Request.ADAPTER.encode(request)
// )
// val response = Rpc.BlockDataviewRecord.RelationOption.Add.Response.ADAPTER.decode(encoded)
// val error = response.error
// if (error != null && error.code != Rpc.BlockDataviewRecord.RelationOption.Add.Response.Error.Code.NULL) {
// throw Exception(error.description)
// } else {
// return response
// }
// }
//
// override fun blockDataViewRecordUpdate(request: Rpc.BlockDataviewRecord.Update.Request): Rpc.BlockDataviewRecord.Update.Response {
// val encoded = Service.blockDataviewRecordUpdate(
// Rpc.BlockDataviewRecord.Update.Request.ADAPTER.encode(request)
// )
// val response = Rpc.BlockDataviewRecord.Update.Response.ADAPTER.decode(encoded)
// val error = response.error
// if (error != null && error.code != Rpc.BlockDataviewRecord.Update.Response.Error.Code.NULL) {
// throw Exception(error.description)
// } else {
// return response
// }
// }
override fun blockDataViewRelationAdd(request: Rpc.BlockDataview.Relation.Add.Request): Rpc.BlockDataview.Relation.Add.Response {
val encoded = Service.blockDataviewRelationAdd(
Rpc.BlockDataview.Relation.Add.Request.ADAPTER.encode(request)
@ -249,6 +199,19 @@ class MiddlewareServiceImplementation @Inject constructor(
}
}
override fun blockDataViewViewSetPosition(request: Rpc.BlockDataview.View.SetPosition.Request): Rpc.BlockDataview.View.SetPosition.Response {
val encoded = Service.blockDataviewViewSetPosition(
Rpc.BlockDataview.View.SetPosition.Request.ADAPTER.encode(request)
)
val response = Rpc.BlockDataview.View.SetPosition.Response.ADAPTER.decode(encoded)
val error = response.error
if (error != null && error.code != Rpc.BlockDataview.View.SetPosition.Response.Error.Code.NULL) {
throw Exception(error.description)
} else {
return response
}
}
override fun blockDataViewViewCreate(request: Rpc.BlockDataview.View.Create.Request): Rpc.BlockDataview.View.Create.Response {
val encoded = Service.blockDataviewViewCreate(
Rpc.BlockDataview.View.Create.Request.ADAPTER.encode(request)

View file

@ -7,6 +7,9 @@ import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.DVViewerType
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.domain.base.fold
import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer
import com.anytypeio.anytype.domain.dataview.interactor.SetDataViewViewerPosition
import com.anytypeio.anytype.presentation.common.BaseListViewModel
import com.anytypeio.anytype.presentation.extension.ObjectStateAnalyticsEvent
import com.anytypeio.anytype.presentation.extension.logEvent
@ -24,7 +27,9 @@ class ManageViewerViewModel(
private val objectState: StateFlow<ObjectState>,
private val session: ObjectSetSession,
private val dispatcher: Dispatcher<Payload>,
private val analytics: Analytics
private val analytics: Analytics,
private val deleteDataViewViewer: DeleteDataViewViewer,
private val setDataViewViewerPosition: SetDataViewViewerPosition
) : BaseListViewModel<ViewerView>() {
val isEditEnabled = MutableStateFlow(false)
@ -50,8 +55,38 @@ class ManageViewerViewModel(
}
}
fun onOrderChanged(ctx: Id, order: List<String>) {
fun onOrderChanged(
ctx: Id,
dv: Id,
newPosition: Int,
newOrder: List<Id>,
) {
val currentOrder = views.value.map { it.id }
if (newOrder == currentOrder) return
val viewer = newOrder.getOrNull(newPosition)
if (viewer != null) {
viewModelScope.launch {
// Workaround for preserving the previously first view as the active view
if (newPosition == 0 && session.currentViewerId.value.isNullOrEmpty()) {
session.currentViewerId.value = views.value.firstOrNull()?.id
}
setDataViewViewerPosition.stream(
params = SetDataViewViewerPosition.Params(
ctx = ctx,
dv = dv,
viewer = viewer,
pos = newPosition
)
).collect { result ->
result.fold(
onSuccess = { dispatcher.send(it) },
onFailure = { Timber.e(it, "Error while changing view order") }
)
}
}
} else {
sendToast("Something went wrong. Please, try again later.")
}
}
fun onViewerActionClicked(view: ViewerView) {
@ -60,6 +95,25 @@ class ManageViewerViewModel(
}
}
fun onDeleteView(
ctx: Id,
dv: Id,
view: ViewerView
) {
viewModelScope.launch {
deleteDataViewViewer(
DeleteDataViewViewer.Params(
ctx = ctx,
dataview = dv,
viewer = view.id
)
).process(
failure = { Timber.e(it, "Error while deleting view") },
success = { dispatcher.send(it) }
)
}
}
fun onButtonEditClicked() {
isEditEnabled.value = !isEditEnabled.value
_views.value = views.value.map { view ->
@ -103,7 +157,9 @@ class ManageViewerViewModel(
private val objectState: StateFlow<ObjectState>,
private val session: ObjectSetSession,
private val dispatcher: Dispatcher<Payload>,
private val analytics: Analytics
private val analytics: Analytics,
private val deleteDataViewViewer: DeleteDataViewViewer,
private val setDataViewViewerPosition: SetDataViewViewerPosition
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@ -111,7 +167,9 @@ class ManageViewerViewModel(
objectState = objectState,
session = session,
dispatcher = dispatcher,
analytics = analytics
analytics = analytics,
deleteDataViewViewer = deleteDataViewViewer,
setDataViewViewerPosition = setDataViewViewerPosition
) as T
}
}

View file

@ -73,6 +73,9 @@ class DefaultObjectStateReducer : ObjectStateReducer {
is Command.DataView.DeleteView -> {
handleDeleteView(state, event)
}
is Command.DataView.OrderViews -> {
handleOrderViews(state, event)
}
is Command.DataView.SetRelation -> {
handelSetRelation(state, event)
}
@ -235,6 +238,33 @@ class DefaultObjectStateReducer : ObjectStateReducer {
}
}
/**
* @see Command.DataView.OrderViews
*/
private fun handleOrderViews(
state: ObjectState,
event: Command.DataView.OrderViews
): ObjectState {
val updateBlockContent = { content: Block.Content.DataView ->
content.copy(
viewers = content.viewers.sortedBy { viewer ->
event.order.indexOf(viewer.id)
}
)
}
return when (state) {
is ObjectState.DataView.Collection -> state.updateBlockContent(
target = event.dv,
blockContentUpdate = updateBlockContent
)
is ObjectState.DataView.Set -> state.updateBlockContent(
target = event.dv,
blockContentUpdate = updateBlockContent
)
else -> state
}
}
/**
* @see Command.DataView.SetRelation
*/