mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
Data view | Performance optimizations (#1474)
This commit is contained in:
parent
e1ab8489a7
commit
8c9d1a0d42
8 changed files with 104 additions and 68 deletions
2
.github/workflows/check.yml
vendored
2
.github/workflows/check.yml
vendored
|
@ -1,7 +1,7 @@
|
|||
on:
|
||||
pull_request:
|
||||
# add "synchronize" in "types", in order to trigger workflow for pull request commit(s) pushes.
|
||||
types: [open]
|
||||
types: [opened]
|
||||
branches: [develop]
|
||||
name: Run debug unit tests
|
||||
jobs:
|
||||
|
|
|
@ -19,7 +19,10 @@ import com.anytypeio.anytype.R
|
|||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.core_ui.extensions.setImageOrNull
|
||||
import com.anytypeio.anytype.core_ui.features.dataview.*
|
||||
import com.anytypeio.anytype.core_ui.features.dataview.ViewerGridAdapter
|
||||
import com.anytypeio.anytype.core_ui.features.dataview.ViewerGridHeaderAdapter
|
||||
import com.anytypeio.anytype.core_ui.features.dataview.ViewerListAdapter
|
||||
import com.anytypeio.anytype.core_ui.features.dataview.ViewerTypeAdapter
|
||||
import com.anytypeio.anytype.core_ui.reactive.*
|
||||
import com.anytypeio.anytype.core_utils.OnSwipeListener
|
||||
import com.anytypeio.anytype.core_utils.ext.argString
|
||||
|
@ -73,12 +76,6 @@ open class ObjectSetFragment :
|
|||
GestureDetector(context, swipeListener)
|
||||
}
|
||||
|
||||
private val viewerTabAdapter by lazy {
|
||||
ViewerTabItemAdapter(
|
||||
onAddNewViewerClicked = { vm.onCreateNewViewerClicked() },
|
||||
onViewerTabClicked = { vm.onViewerTabClicked(it) }
|
||||
)
|
||||
}
|
||||
private val viewerGridHeaderAdapter by lazy {
|
||||
ViewerGridHeaderAdapter(
|
||||
onCreateNewColumnClicked = { vm.onAddNewDataViewRelation() }
|
||||
|
@ -345,7 +342,6 @@ open class ObjectSetFragment :
|
|||
super.onStart()
|
||||
jobs += lifecycleScope.subscribe(vm.commands) { observeCommands(it) }
|
||||
jobs += lifecycleScope.subscribe(vm.header.filterNotNull()) { observeHeader(it) }
|
||||
jobs += lifecycleScope.subscribe(vm.viewerTabs) { viewerTabAdapter.update(it) }
|
||||
jobs += lifecycleScope.subscribe(vm.viewerGrid) { observeGrid(it) }
|
||||
vm.onStart(ctx)
|
||||
}
|
||||
|
|
|
@ -5,33 +5,28 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.features.dataview.diff.GridRowDiffUtil
|
||||
import com.anytypeio.anytype.presentation.sets.CellAction
|
||||
import com.anytypeio.anytype.presentation.sets.model.CellView
|
||||
import com.anytypeio.anytype.presentation.sets.model.Viewer
|
||||
import kotlinx.android.synthetic.main.item_viewer_grid_row.view.*
|
||||
import timber.log.Timber
|
||||
|
||||
class ViewerGridAdapter(
|
||||
private var items: List<Viewer.GridView.Row> = emptyList(),
|
||||
private val onCellClicked: (CellView) -> Unit,
|
||||
private val onCellAction: (CellAction) -> Unit,
|
||||
private val onObjectHeaderClicked: (String, String) -> Unit
|
||||
) : RecyclerView.Adapter<ViewerGridAdapter.RecordHolder>() {
|
||||
) : ListAdapter<Viewer.GridView.Row, ViewerGridAdapter.RecordHolder>(GridDiffUtil) {
|
||||
|
||||
var recordNamePositionX = 0f
|
||||
|
||||
fun update(update: List<Viewer.GridView.Row>) {
|
||||
val diff = DiffUtil.calculateDiff(GridRowDiffUtil(old = items, new = update))
|
||||
items = update
|
||||
diff.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
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 {
|
||||
|
@ -43,16 +38,14 @@ class ViewerGridAdapter(
|
|||
}
|
||||
return RecordHolder(view).apply {
|
||||
itemView.headerContainer.setOnClickListener {
|
||||
val item = items[bindingAdapterPosition]
|
||||
val item = getItem(bindingAdapterPosition)
|
||||
onObjectHeaderClicked(item.id, item.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = items.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecordHolder, position: Int) {
|
||||
holder.bind(items[position])
|
||||
holder.bind(getItem(position))
|
||||
}
|
||||
|
||||
override fun onViewAttachedToWindow(holder: RecordHolder) {
|
||||
|
@ -72,6 +65,7 @@ class ViewerGridAdapter(
|
|||
fun bind(
|
||||
row: Viewer.GridView.Row
|
||||
) {
|
||||
Timber.d("Binding record holder")
|
||||
itemView.objectIcon.setIcon(
|
||||
emoji = row.emoji,
|
||||
image = row.image,
|
||||
|
@ -81,4 +75,15 @@ class ViewerGridAdapter(
|
|||
adapter.update(row.cells)
|
||||
}
|
||||
}
|
||||
|
||||
object GridDiffUtil : DiffUtil.ItemCallback<Viewer.GridView.Row>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: Viewer.GridView.Row,
|
||||
newItem: Viewer.GridView.Row
|
||||
): Boolean = oldItem.id == newItem.id
|
||||
override fun areContentsTheSame(
|
||||
oldItem: Viewer.GridView.Row,
|
||||
newItem: Viewer.GridView.Row
|
||||
): Boolean = oldItem == newItem
|
||||
}
|
||||
}
|
|
@ -9,21 +9,24 @@ import com.anytypeio.anytype.core_ui.features.dataview.diff.CellViewDiffUtil
|
|||
import com.anytypeio.anytype.core_ui.features.dataview.holders.*
|
||||
import com.anytypeio.anytype.presentation.sets.CellAction
|
||||
import com.anytypeio.anytype.presentation.sets.model.CellView
|
||||
import timber.log.Timber
|
||||
|
||||
class ViewerGridCellsAdapter(
|
||||
private var cells: List<CellView> = listOf(),
|
||||
var cells: List<CellView> = listOf(),
|
||||
private val onCellClicked: (CellView) -> Unit,
|
||||
private val onCellAction: (CellAction) -> Unit
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
fun update(update: List<CellView>) {
|
||||
Timber.d("Updating cells: update size - ${update.size}, current - ${cells.size}")
|
||||
// TODO maybe disable detectMoves
|
||||
val diff = DiffUtil.calculateDiff(CellViewDiffUtil(old = cells, new = update))
|
||||
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)
|
||||
//todo Take cells width from columns width property
|
||||
return when (viewType) {
|
||||
|
@ -173,6 +176,7 @@ 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)
|
||||
|
|
|
@ -1,69 +1,88 @@
|
|||
package com.anytypeio.anytype.core_ui.features.dataview
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
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
|
||||
import com.anytypeio.anytype.presentation.sets.model.ColumnView
|
||||
import kotlinx.android.synthetic.main.viewer_cell.view.*
|
||||
import timber.log.Timber
|
||||
|
||||
class ViewerGridHeaderAdapter(
|
||||
items: List<ColumnView> = emptyList(),
|
||||
val onCreateNewColumnClicked: () -> Unit,
|
||||
) : AbstractAdapter<ColumnView>(items) {
|
||||
) : ListAdapter<ColumnView, ViewerGridHeaderAdapter.HeaderViewHolder>(ColumnHeaderDiffCallback) {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int,
|
||||
): AbstractViewHolder<ColumnView> = when (viewType) {
|
||||
HEADER_TYPE -> {
|
||||
DefaultHolder(
|
||||
view = inflate(parent, R.layout.item_grid_column_header)
|
||||
)
|
||||
}
|
||||
PLUS_TYPE -> {
|
||||
PlusHolder(
|
||||
view = inflate(parent, R.layout.item_grid_column_header_plus)
|
||||
).apply {
|
||||
itemView.setOnClickListener {
|
||||
onCreateNewColumnClicked()
|
||||
}
|
||||
): HeaderViewHolder = when (viewType) {
|
||||
HEADER_TYPE -> HeaderViewHolder.DefaultHolder.create(parent)
|
||||
PLUS_TYPE -> HeaderViewHolder.PlusHolder.create(parent).apply {
|
||||
itemView.setOnClickListener {
|
||||
onCreateNewColumnClicked()
|
||||
}
|
||||
}
|
||||
else -> throw IllegalStateException("Unexpected view type: $viewType")
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AbstractViewHolder<ColumnView>, position: Int) {
|
||||
if (position < items.size) super.onBindViewHolder(holder, position)
|
||||
override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
|
||||
if (holder is HeaderViewHolder.DefaultHolder) holder.bind(getItem(position))
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int) = if (position == items.size) {
|
||||
override fun getItemViewType(position: Int) = if (position == super.getItemCount()) {
|
||||
PLUS_TYPE
|
||||
} else {
|
||||
HEADER_TYPE
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if (super.getItemCount() == 0)
|
||||
0
|
||||
else
|
||||
super.getItemCount() + 1
|
||||
}
|
||||
override fun getItemCount(): Int = if (super.getItemCount() == 0) 0 else super.getItemCount() + 1
|
||||
|
||||
class DefaultHolder(view: View) : AbstractViewHolder<ColumnView>(view) {
|
||||
override fun bind(item: ColumnView) {
|
||||
itemView.cellText.text = item.text
|
||||
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
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(
|
||||
parent: ViewGroup
|
||||
): DefaultHolder = DefaultHolder(
|
||||
LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.item_grid_column_header,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
class PlusHolder(view: View) : HeaderViewHolder(view) {
|
||||
companion object {
|
||||
fun create(
|
||||
parent: ViewGroup
|
||||
): PlusHolder = PlusHolder(
|
||||
LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.item_grid_column_header_plus,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PlusHolder(view: View) : AbstractViewHolder<ColumnView>(view) {
|
||||
override fun bind(item: ColumnView) {}
|
||||
}
|
||||
|
||||
override fun update(update: List<ColumnView>) {
|
||||
items = update
|
||||
notifyDataSetChanged()
|
||||
object ColumnHeaderDiffCallback : DiffUtil.ItemCallback<ColumnView>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: ColumnView,
|
||||
newItem: ColumnView
|
||||
): Boolean = oldItem.key == newItem.key
|
||||
override fun areContentsTheSame(
|
||||
oldItem: ColumnView,
|
||||
newItem: ColumnView
|
||||
): Boolean = oldItem == newItem
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -52,6 +52,7 @@ class ViewerTypeAdapter(
|
|||
override fun getItemCount(): Int = items.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
Timber.d("onBindViewHolder")
|
||||
when (holder) {
|
||||
is GridHolder -> holder.bind(
|
||||
viewer = items[position] as Viewer.GridView,
|
||||
|
@ -89,11 +90,18 @@ class ViewerTypeAdapter(
|
|||
headerAdapter: ViewerGridHeaderAdapter
|
||||
) {
|
||||
Timber.d("Binding grid")
|
||||
headerAdapter.update(viewer.columns)
|
||||
gridAdapter.update(viewer.rows)
|
||||
|
||||
if (columns.adapter == null) columns.adapter = headerAdapter
|
||||
if (rows.adapter == null) rows.adapter = gridAdapter
|
||||
if (columns.adapter == null) {
|
||||
Timber.d("Setting columns adapter")
|
||||
columns.adapter = headerAdapter
|
||||
}
|
||||
if (rows.adapter == null) {
|
||||
Timber.d("Setting rows adapter")
|
||||
rows.adapter = gridAdapter
|
||||
}
|
||||
|
||||
headerAdapter.submitList(viewer.columns)
|
||||
gridAdapter.submitList(viewer.rows)
|
||||
|
||||
itemView.horizontalScrollView.setOnScrollChangeListener { _, scrollX, _, _, _ ->
|
||||
val translationX = scrollX.toFloat()
|
||||
|
@ -106,7 +114,6 @@ class ViewerTypeAdapter(
|
|||
}
|
||||
|
||||
class ListHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
fun bind(adapter: ViewerListAdapter) {
|
||||
itemView.rvRows.adapter = adapter
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.anytypeio.anytype.core_ui.features.dataview.diff
|
|||
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.anytypeio.anytype.presentation.sets.model.CellView
|
||||
import timber.log.Timber
|
||||
|
||||
class CellViewDiffUtil(
|
||||
private val old: List<CellView>,
|
||||
|
@ -11,13 +12,13 @@ class CellViewDiffUtil(
|
|||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
val oldItem = old[oldItemPosition]
|
||||
val newItem = new[newItemPosition]
|
||||
return (oldItem.id == newItem.id)
|
||||
return (oldItem.id == newItem.id).also { Timber.d("areItemsTheSame: $it") }
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
val oldItem = old[oldItemPosition]
|
||||
val newItem = new[newItemPosition]
|
||||
return oldItem == newItem
|
||||
return oldItem == newItem.also { Timber.d("areContentsTheSame: $it") }
|
||||
}
|
||||
|
||||
override fun getOldListSize(): Int = old.size
|
||||
|
|
|
@ -17,7 +17,11 @@ class GridRowDiffUtil(
|
|||
override fun areContentsTheSame(
|
||||
oldItemPosition: Int,
|
||||
newItemPosition: Int
|
||||
): Boolean = false
|
||||
): Boolean {
|
||||
val oldItem = old[oldItemPosition]
|
||||
val newItem = new[newItemPosition]
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
override fun getOldListSize(): Int = old.size
|
||||
override fun getNewListSize(): Int = new.size
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue