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

App | Feature | Object types sorting (#1910)

* add weight to object types views

* add task url

* fixes

* fix

* fix

* remove nullable
This commit is contained in:
Konstantin Ivanov 2021-11-09 18:28:44 +03:00 committed by GitHub
parent db125cf040
commit a02b9feb04
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 426 additions and 14 deletions

View file

@ -59,9 +59,36 @@ data class ObjectType(
const val VIDEO_URL = "_otvideo"
const val AUDIO_URL = "_otaudio"
const val SET_URL = "_otset"
const val TASK_URL = "_ottask"
const val DATE_URL = "_otdate"
const val PROFILE_URL = "_otprofile" //contains User Profile page and Anytype Person page
const val NOTE_URL = "_otnote"
const val WORKSPACE_URL = "_otspace"
}
}
class ObjectTypeComparator : Comparator<ObjectType> {
override fun compare(o1: ObjectType, o2: ObjectType): Int {
val o1Url = o1.url
val o2Url = o2.url
if (o1Url == o2Url) return 0
if (o1Url == ObjectType.PAGE_URL && o2Url != ObjectType.PAGE_URL) return -1
if (o1Url != ObjectType.PAGE_URL && o2Url == ObjectType.PAGE_URL) return 1
if (o1Url == ObjectType.NOTE_URL && o2Url != ObjectType.NOTE_URL) return -1
if (o1Url != ObjectType.NOTE_URL && o2Url == ObjectType.NOTE_URL) return 1
if (o1Url == ObjectType.SET_URL && o2Url != ObjectType.SET_URL) return -1
if (o1Url != ObjectType.SET_URL && o2Url == ObjectType.SET_URL) return 1
if (o1Url == ObjectType.TASK_URL && o2Url != ObjectType.TASK_URL) return -1
if (o1Url != ObjectType.TASK_URL && o2Url == ObjectType.TASK_URL) return 1
val o1Name = o1.name
val o2Name = o2.name
return o1Name.compareTo(o2Name)
}
}

View file

@ -28,7 +28,6 @@ class ViewerGridAdapter(
parent: ViewGroup,
viewType: Int
): RecordHolder {
Timber.d("OnCreateViewHolder")
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.item_viewer_grid_row, parent, false)
view.rowCellRecycler.apply {
@ -48,7 +47,6 @@ class ViewerGridAdapter(
}
override fun onBindViewHolder(holder: RecordHolder, position: Int) {
Timber.d("Binding record holder")
holder.bindObjectHeader(getItem(position))
holder.bindObjectCells(getItem(position))
}
@ -81,7 +79,6 @@ class ViewerGridAdapter(
val adapter get() = itemView.rowCellRecycler.adapter as ViewerGridCellsAdapter
fun bindObjectHeader(row: Viewer.GridView.Row) {
Timber.d("Binding object header")
when (row.layout) {
ObjectType.Layout.TODO -> {
itemView.objectIcon.visible()
@ -115,7 +112,6 @@ class ViewerGridAdapter(
}
fun bindObjectCells(row: Viewer.GridView.Row) {
Timber.d("Binding object cells")
adapter.update(row.cells)
}
}

View file

@ -17,14 +17,12 @@ class ViewerGridCellsAdapter(
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
fun update(update: List<CellView>) {
Timber.d("Updating cells: update size - ${update.size}, current - ${cells.size}")
val diff = DiffUtil.calculateDiff(CellViewDiffUtil(old = cells, new = update), false)
cells = update
diff.dispatchUpdatesTo(this)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
Timber.d("onCreateViewHolder")
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
HOLDER_DESCRIPTION -> {
@ -206,7 +204,6 @@ class ViewerGridCellsAdapter(
override fun getItemCount(): Int = cells.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
Timber.d("onBindViewHolder")
when (holder) {
is DVGridCellDescriptionHolder -> holder.bind(cells[position] as CellView.Description)
is DVGridCellDateHolder -> holder.bind(cells[position] as CellView.Date)

View file

@ -37,7 +37,6 @@ class ViewerGridHeaderAdapter() :
sealed class HeaderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
class DefaultHolder(view: View) : HeaderViewHolder(view) {
fun bind(item: ColumnView) {
Timber.d("Binding default holder")
itemView.cellText.text = item.text
}

View file

@ -1,6 +1,7 @@
package com.anytypeio.anytype.domain.dataview.interactor
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeComparator
import com.anytypeio.anytype.core_models.SmartBlockType
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -13,9 +14,9 @@ class GetCompatibleObjectTypes(
) : BaseUseCase<List<ObjectType>, GetCompatibleObjectTypes.Params>() {
override suspend fun run(params: Params) = safe {
repo.getObjectTypes().filter { oType ->
oType.smartBlockTypes.contains(params.smartBlockType) && !oType.isArchived
}
repo.getObjectTypes()
.filter { it.smartBlockTypes.contains(params.smartBlockType) && !it.isArchived }
.sortedWith(ObjectTypeComparator())
}
/**

View file

@ -0,0 +1,392 @@
package com.anytypeio.anytype.domain.block.interactor
import com.anytypeio.anytype.core_models.CoroutineTestRule
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.SmartBlockType
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.common.MockDataFactory
import com.anytypeio.anytype.domain.dataview.interactor.GetCompatibleObjectTypes
import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.stub
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import kotlin.test.assertEquals
class GetCompatibleObjectTypesTest {
@ExperimentalCoroutinesApi
@get:Rule
var rule = CoroutineTestRule()
@Mock
lateinit var repository: BlockRepository
lateinit var getCompatibleObjectTypes: GetCompatibleObjectTypes
@Before
fun before() {
MockitoAnnotations.initMocks(this)
getCompatibleObjectTypes = GetCompatibleObjectTypes(repository)
}
@Test
fun shouldFilterResultBySmartBlockType() {
val type1 = ObjectType(
url = ObjectType.PAGE_URL,
name = "AAA",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type2 = ObjectType(
url = ObjectType.PAGE_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.WORKSPACE),
isArchived = true,
isReadOnly = false
)
val type3 = ObjectType(
url = ObjectType.PAGE_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.DATE),
isArchived = false,
isReadOnly = false
)
val type4 = ObjectType(
url = ObjectType.PAGE_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.SET),
isArchived = false,
isReadOnly = false
)
val type5 = ObjectType(
url = ObjectType.PAGE_URL,
name = "ZZZ",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.ARCHIVE, SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
repository.stub {
onBlocking { getObjectTypes() } doReturn listOf(type1, type2, type3, type4, type5)
}
runBlocking {
val params = GetCompatibleObjectTypes.Params(smartBlockType = SmartBlockType.PAGE)
val expected = listOf(type1, type5)
getCompatibleObjectTypes.run(params).process(
failure = {},
success = {
assertEquals(expected, it)
}
)
}
}
@Test
fun shouldSortResultByUrl() {
val type1 = ObjectType(
url = ObjectType.TEMPLATE_URL,
name = "QName",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type2 = ObjectType(
url = ObjectType.SET_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type3 = ObjectType(
url = ObjectType.PAGE_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type4 = ObjectType(
url = ObjectType.TASK_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type5 = ObjectType(
url = ObjectType.NOTE_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.ARCHIVE, SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type6 = ObjectType(
url = ObjectType.AUDIO_URL,
name = "NName",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.ARCHIVE, SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type7 = ObjectType(
url = ObjectType.RELATION_URL,
name = "XName",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.ANYTYPE_PROFILE, SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type8 = ObjectType(
url = "_customType",
name = "AName",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.CUSTOM_OBJECT_TYPE, SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
repository.stub {
onBlocking { getObjectTypes() } doReturn listOf(
type1,
type2,
type3,
type4,
type5,
type6,
type7,
type8
)
}
runBlocking {
val params = GetCompatibleObjectTypes.Params(smartBlockType = SmartBlockType.PAGE)
val expected = listOf(type3, type5, type2, type4, type8, type6, type1, type7)
getCompatibleObjectTypes.run(params).process(
failure = {},
success = {
assertEquals(expected, it)
}
)
}
}
@Test
fun shouldSortResultByTypeUrlAndArchived() {
val type1 = ObjectType(
url = ObjectType.TEMPLATE_URL,
name = "QName",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = true,
isReadOnly = false
)
val type2 = ObjectType(
url = ObjectType.SET_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type3 = ObjectType(
url = ObjectType.PAGE_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type4 = ObjectType(
url = ObjectType.TASK_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.PAGE),
isArchived = true,
isReadOnly = false
)
val type5 = ObjectType(
url = ObjectType.NOTE_URL,
name = MockDataFactory.randomString(),
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.ARCHIVE, SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type6 = ObjectType(
url = ObjectType.AUDIO_URL,
name = "NName",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.ARCHIVE, SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
val type7 = ObjectType(
url = ObjectType.RELATION_URL,
name = "XName",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.ANYTYPE_PROFILE),
isArchived = false,
isReadOnly = false
)
val type8 = ObjectType(
url = "_customType",
name = "AName",
relations = emptyList(),
layout = ObjectType.Layout.values().random(),
emoji = MockDataFactory.randomString(),
description = MockDataFactory.randomString(),
isHidden = MockDataFactory.randomBoolean(),
smartBlockTypes = listOf(SmartBlockType.CUSTOM_OBJECT_TYPE, SmartBlockType.PAGE),
isArchived = false,
isReadOnly = false
)
repository.stub {
onBlocking { getObjectTypes() } doReturn listOf(
type1,
type2,
type3,
type4,
type5,
type6,
type7,
type8
)
}
runBlocking {
val params = GetCompatibleObjectTypes.Params(smartBlockType = SmartBlockType.PAGE)
val expected = listOf(type3, type5, type2, type8, type6)
getCompatibleObjectTypes.run(params).process(
failure = {},
success = {
assertEquals(expected, it)
}
)
}
}
}

View file

@ -5265,10 +5265,10 @@ class EditorViewModel(
getDefaultEditorType.invoke(Unit).proceed(
failure = { Timber.e(it, "Error while getting default object type") },
success = { response ->
val sorted = listOf(ObjectTypeView.Search) + views.toMutableList()
.sortByType(response.type)
val filtered = views.filter { it.id != response.type }
val result = listOf(ObjectTypeView.Search) + filtered
controlPanelInteractor.onEvent(
ControlPanelMachine.Event.ObjectTypesWidgetEvent.Show(sorted)
ControlPanelMachine.Event.ObjectTypesWidgetEvent.Show(result)
)
}
)