mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-122 Editor | Enhancement | Simple tables, cell menu, cells selecting (#2696)
* DROID-132 cell selection state + logic + tests * DROID-132 added cell border, cell rect classes * DROID-132 refactoring * DROID-132 refactoring * DROID-132 cell selection decoration * DROID-132 remove legacy * DROID-132 table block holder, add selection decoration * DROID-132 delete legacy clicks * DROID-132 cell model update * DROID-132 simple table widget events * DROID-132 editor table mode * DROID-132 table cell extension * DROID-132 legacy classes * DROID-132 delete legacy * DROID-132 update cell clicks * DROID-132 cells extensions * DROID-132 update item decorations * DROID-132 cell selection top toolbar * DROID-132 select cells, show widget * DROID-132 clear content command * DROID-132 clear content use case * DROID-132 menu item click * DROID-132 table delegate * DROID-132 fixes * DROID-132 refactoring * DROID-132 fix hide simple widget event * DROID-132 refactoring * DROID-132 test fixes * DROID-132 fix tests * DROID-132 turn off buttons * DROID-122 delete legacy delegate * DROID-122 table block diff util * DROID-122 add selected cells to table view model * DROID-122 rename param * DROID-122 add selection state to table block holder * DROID-122 delete * DROID-122 mapping * DROID-122 rename funcs * DROID-122 fix tests * DROID-122 update selection logic * DROID-122 pr fix * DROID-122 code style * DROID-122 pr fixes Co-authored-by: konstantiniiv <ki@anytype.io>
This commit is contained in:
parent
eecdc5e690
commit
b30d60f4df
48 changed files with 1735 additions and 340 deletions
|
@ -20,6 +20,7 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
|||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.base.Result
|
||||
import com.anytypeio.anytype.domain.block.UpdateDivider
|
||||
import com.anytypeio.anytype.domain.block.interactor.ClearBlockContent
|
||||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.DuplicateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.MergeBlocks
|
||||
|
@ -88,7 +89,6 @@ import com.anytypeio.anytype.presentation.editor.editor.InternalDetailModificati
|
|||
import com.anytypeio.anytype.presentation.editor.editor.Orchestrator
|
||||
import com.anytypeio.anytype.presentation.editor.editor.Proxy
|
||||
import com.anytypeio.anytype.presentation.editor.editor.pattern.DefaultPatternMatcher
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
|
||||
import com.anytypeio.anytype.presentation.editor.selection.SelectionStateHolder
|
||||
import com.anytypeio.anytype.presentation.editor.template.DefaultEditorTemplateDelegate
|
||||
|
@ -190,6 +190,7 @@ open class EditorTestSetup {
|
|||
lateinit var turnIntoStyle: TurnIntoStyle
|
||||
lateinit var setObjectType: SetObjectType
|
||||
lateinit var objectToSet: ConvertObjectToSet
|
||||
lateinit var clearBlockContent: ClearBlockContent
|
||||
|
||||
lateinit var getDefaultEditorType: GetDefaultEditorType
|
||||
|
||||
|
@ -243,9 +244,6 @@ open class EditorTestSetup {
|
|||
@Mock
|
||||
lateinit var fillTableRow: FillTableRow
|
||||
|
||||
@Mock
|
||||
lateinit var simpleTableDelegate: SimpleTableDelegate
|
||||
|
||||
val root: String = "rootId123"
|
||||
|
||||
private val urlBuilder by lazy {
|
||||
|
@ -289,6 +287,7 @@ open class EditorTestSetup {
|
|||
getSearchObjects = SearchObjects(repo)
|
||||
interceptThreadStatus = InterceptThreadStatus(channel = threadStatusChannel)
|
||||
downloadUnsplashImage = DownloadUnsplashImage(unsplashRepository)
|
||||
clearBlockContent = ClearBlockContent(repo)
|
||||
downloadFile = DownloadFile(
|
||||
downloader = mock(),
|
||||
context = Dispatchers.Main
|
||||
|
@ -388,7 +387,8 @@ open class EditorTestSetup {
|
|||
setObjectType = setObjectType,
|
||||
createBookmarkBlock = createBookmarkBlock,
|
||||
createTable = createTable,
|
||||
fillTableRow = fillTableRow
|
||||
fillTableRow = fillTableRow,
|
||||
clearBlockContent = clearBlockContent
|
||||
),
|
||||
createNewDocument = createNewDocument,
|
||||
interceptThreadStatus = interceptThreadStatus,
|
||||
|
@ -409,7 +409,6 @@ open class EditorTestSetup {
|
|||
setDocImageIcon = setDocImageIcon,
|
||||
editorTemplateDelegate = editorTemplateDelegate,
|
||||
createNewObject = createNewObject,
|
||||
simpleTablesDelegate = simpleTableDelegate,
|
||||
objectToSet = objectToSet
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
|||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.UpdateDivider
|
||||
import com.anytypeio.anytype.domain.block.interactor.ClearBlockContent
|
||||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.DuplicateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.MergeBlocks
|
||||
|
@ -93,8 +94,6 @@ import com.anytypeio.anytype.presentation.editor.editor.Interactor
|
|||
import com.anytypeio.anytype.presentation.editor.editor.InternalDetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.editor.editor.Orchestrator
|
||||
import com.anytypeio.anytype.presentation.editor.editor.pattern.DefaultPatternMatcher
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.DefaultSimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
|
||||
import com.anytypeio.anytype.presentation.editor.selection.SelectionStateHolder
|
||||
import com.anytypeio.anytype.presentation.editor.template.DefaultEditorTemplateDelegate
|
||||
|
@ -224,7 +223,6 @@ object EditorSessionModule {
|
|||
setDocImageIcon: SetDocumentImageIcon,
|
||||
editorTemplateDelegate: EditorTemplateDelegate,
|
||||
createNewObject: CreateNewObject,
|
||||
simpleTableDelegate: SimpleTableDelegate,
|
||||
objectToSet: ConvertObjectToSet
|
||||
): EditorViewModelFactory = EditorViewModelFactory(
|
||||
openPage = openPage,
|
||||
|
@ -257,7 +255,6 @@ object EditorSessionModule {
|
|||
setDocImageIcon = setDocImageIcon,
|
||||
editorTemplateDelegate = editorTemplateDelegate,
|
||||
createNewObject = createNewObject,
|
||||
simpleTablesDelegate = simpleTableDelegate,
|
||||
objectToSet = objectToSet
|
||||
)
|
||||
|
||||
|
@ -285,12 +282,6 @@ object EditorSessionModule {
|
|||
applyTemplate = applyTemplate
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideSimpleTableDelegate(
|
||||
): SimpleTableDelegate = DefaultSimpleTableDelegate()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
fun provideDefaultBlockViewRenderer(
|
||||
|
@ -366,7 +357,8 @@ object EditorSessionModule {
|
|||
setRelationKey: SetRelationKey,
|
||||
analytics: Analytics,
|
||||
updateBlocksMark: UpdateBlocksMark,
|
||||
middlewareShareDownloader: MiddlewareShareDownloader
|
||||
middlewareShareDownloader: MiddlewareShareDownloader,
|
||||
clearBlockContent: ClearBlockContent
|
||||
): Orchestrator = Orchestrator(
|
||||
stores = storage,
|
||||
createBlock = createBlock,
|
||||
|
@ -408,6 +400,7 @@ object EditorSessionModule {
|
|||
setObjectType = setObjectType,
|
||||
createTable = createTable,
|
||||
fillTableRow = fillTableRow,
|
||||
clearBlockContent = clearBlockContent
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1000,6 +993,13 @@ object EditorUseCaseModule {
|
|||
uriFileProvider = fileProvider
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideBlockListClearContent(
|
||||
repo: BlockRepository
|
||||
): ClearBlockContent = ClearBlockContent(repo)
|
||||
|
||||
@Module
|
||||
interface Bindings {
|
||||
|
||||
|
|
|
@ -109,7 +109,6 @@ import com.anytypeio.anytype.presentation.editor.editor.control.ControlPanelStat
|
|||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.sam.ScrollAndMoveTarget
|
||||
import com.anytypeio.anytype.presentation.editor.editor.sam.ScrollAndMoveTargetDescriptor
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetViewState
|
||||
import com.anytypeio.anytype.presentation.editor.markup.MarkupColorView
|
||||
import com.anytypeio.anytype.presentation.editor.model.EditorFooter
|
||||
import com.anytypeio.anytype.presentation.editor.template.SelectTemplateViewState
|
||||
|
@ -481,20 +480,6 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
}
|
||||
}
|
||||
}
|
||||
jobs += subscribe(vm.simpleTablesViewState) { state ->
|
||||
val behavior = BottomSheetBehavior.from(binding.simpleTableWidget)
|
||||
when (state) {
|
||||
is SimpleTableWidgetViewState.Active -> {
|
||||
binding.simpleTableWidget.onStateChanged(state = state.state)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
behavior.addBottomSheetCallback(onHideBottomSheetCallback)
|
||||
}
|
||||
SimpleTableWidgetViewState.Idle -> {
|
||||
behavior.removeBottomSheetCallback(onHideBottomSheetCallback)
|
||||
behavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vm.onStart(id = extractDocumentId())
|
||||
super.onStart()
|
||||
|
@ -615,6 +600,13 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
.onEach { vm.onExitMultiSelectModeClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.cellSelectionTopToolbar
|
||||
.doneButton
|
||||
.clicks()
|
||||
.throttleFirst()
|
||||
.onEach { vm.onCellsSelectionDoneClick() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.bottomToolbar
|
||||
.homeClicks()
|
||||
.onEach { vm.onHomeButtonClicked() }
|
||||
|
@ -677,6 +669,10 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
}
|
||||
}
|
||||
|
||||
binding.simpleTableWidget.setListener {
|
||||
vm.onSimpleTableWidgetItemClicked(it)
|
||||
}
|
||||
|
||||
binding.undoRedoToolbar.undo.clicks()
|
||||
.throttleFirst()
|
||||
.onEach {
|
||||
|
@ -755,6 +751,8 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
BottomSheetBehavior.STATE_HIDDEN
|
||||
BottomSheetBehavior.from(binding.typeHasTemplateToolbar).state =
|
||||
BottomSheetBehavior.STATE_HIDDEN
|
||||
BottomSheetBehavior.from(binding.simpleTableWidget).state =
|
||||
BottomSheetBehavior.STATE_HIDDEN
|
||||
|
||||
observeNavBackStack()
|
||||
}
|
||||
|
@ -1558,6 +1556,46 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
binding.objectTypesToolbar.clear()
|
||||
}
|
||||
}
|
||||
|
||||
state.simpleTableWidget.apply {
|
||||
val behavior = BottomSheetBehavior.from(binding.simpleTableWidget)
|
||||
if (isVisible) {
|
||||
binding.simpleTableWidget.onStateChanged(
|
||||
cellItems = state.simpleTableWidget.cellItems,
|
||||
rowItems = state.simpleTableWidget.rowItems,
|
||||
columnItems = state.simpleTableWidget.columnItems
|
||||
)
|
||||
if (behavior.state == BottomSheetBehavior.STATE_HIDDEN) {
|
||||
keyboardDelayJobs += lifecycleScope.launch {
|
||||
if (binding.recycler.itemDecorationCount == 0) {
|
||||
binding.recycler.addItemDecoration(styleToolbarFooter)
|
||||
}
|
||||
proceedWithHidingSoftInput()
|
||||
delayKeyboardHide(insets)
|
||||
behavior.apply {
|
||||
setState(BottomSheetBehavior.STATE_EXPANDED)
|
||||
addBottomSheetCallback(onHideBottomSheetCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (behavior.state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||
behavior.removeBottomSheetCallback(onHideBottomSheetCallback)
|
||||
behavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.cellsSelectTopWidget.apply {
|
||||
if (isVisible) {
|
||||
binding.cellSelectionTopToolbar.showWithAnimation()
|
||||
binding.cellSelectionTopToolbar.setCellSelectionText(count)
|
||||
} else {
|
||||
binding.cellSelectionTopToolbar.hideWithAnimation {
|
||||
if (hasBinding) binding.topToolbar.visible()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applySlideTransition(transTarget: View, transDuration: Long, transRoot: ViewGroup) {
|
||||
|
|
|
@ -58,6 +58,16 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.toolbar.MultiSelectTopToolbarWidget
|
||||
android:id="@+id/cellSelectionTopToolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="@color/defaultCanvasColor"
|
||||
android:translationY="-48dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.toolbar.BlockToolbarWidget
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -244,6 +244,15 @@ class BlockViewDiffUtil(
|
|||
}
|
||||
}
|
||||
|
||||
if (newBlock is BlockView.Table && oldBlock is BlockView.Table) {
|
||||
if (newBlock.cells != oldBlock.cells) {
|
||||
changes.add(TABLE_CELLS_CHANGED)
|
||||
}
|
||||
if (newBlock.selectedCellsIds != oldBlock.selectedCellsIds) {
|
||||
changes.add(TABLE_CELLS_SELECTION_CHANGED)
|
||||
}
|
||||
}
|
||||
|
||||
return if (changes.isNotEmpty())
|
||||
Payload(changes).also { Timber.d("Returning payload: $it") }
|
||||
else
|
||||
|
@ -335,5 +344,8 @@ class BlockViewDiffUtil(
|
|||
|
||||
const val DECORATION_CHANGED = 27
|
||||
const val CALLOUT_ICON_CHANGED = 28
|
||||
|
||||
const val TABLE_CELLS_SELECTION_CHANGED = 340
|
||||
const val TABLE_CELLS_CHANGED = 341
|
||||
}
|
||||
}
|
|
@ -52,18 +52,11 @@ class TableBlockAdapter(
|
|||
val block = item.block
|
||||
if (block == null) {
|
||||
clickListener(
|
||||
ListenerType.TableEmptyCell(
|
||||
cellId = item.getId(),
|
||||
rowId = item.rowId,
|
||||
tableId = tableBlockId
|
||||
)
|
||||
ListenerType.TableEmptyCell(cell = item)
|
||||
)
|
||||
} else {
|
||||
clickListener(
|
||||
ListenerType.TableTextCell(
|
||||
tableId = tableBlockId,
|
||||
cellId = block.id
|
||||
)
|
||||
ListenerType.TableTextCell(cell = item)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,10 +60,7 @@ class TableEditableCellsAdapter(
|
|||
val pos = bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
clicked(
|
||||
ListenerType.TableTextCell(
|
||||
tableId = tableBlockId,
|
||||
cellId = items[pos].getId()
|
||||
)
|
||||
ListenerType.TableTextCell(cell = items[pos])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -123,13 +120,8 @@ class TableEditableCellsAdapter(
|
|||
itemView.setOnClickListener {
|
||||
val pos = bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
val item = items[bindingAdapterPosition]
|
||||
clicked(
|
||||
ListenerType.TableEmptyCell(
|
||||
cellId = item.getId(),
|
||||
rowId = item.rowId,
|
||||
tableId = tableBlockId
|
||||
)
|
||||
ListenerType.TableEmptyCell(cell = items[pos])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,14 @@ import com.anytypeio.anytype.core_ui.layout.TableHorizontalItemDivider
|
|||
import com.anytypeio.anytype.core_ui.layout.TableVerticalItemDivider
|
||||
import com.anytypeio.anytype.core_models.ThemeColor
|
||||
import com.anytypeio.anytype.core_ui.features.table.TableEditableCellsAdapter
|
||||
import com.anytypeio.anytype.core_ui.layout.TableCellSelectionDecoration
|
||||
import com.anytypeio.anytype.core_utils.ext.containsItemDecoration
|
||||
import com.anytypeio.anytype.presentation.BuildConfig
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.mention.MentionEvent
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
|
||||
import com.anytypeio.anytype.presentation.editor.selection.TableCellsSelectionState
|
||||
|
||||
class TableBlockHolder(
|
||||
binding: ItemBlockTableBinding,
|
||||
|
@ -37,6 +40,12 @@ class TableBlockHolder(
|
|||
val recycler: RecyclerView = binding.recyclerTable
|
||||
private val selected = binding.selected
|
||||
|
||||
private val cellsSelectionState = TableCellsSelectionState()
|
||||
|
||||
private val cellSelectionDecoration: TableCellSelectionDecoration = TableCellSelectionDecoration(
|
||||
drawable = binding.root.context.drawable(R.drawable.cell_top_border)
|
||||
)
|
||||
|
||||
private val tableAdapter = TableBlockAdapter(
|
||||
differ = TableCellsDiffUtil,
|
||||
clickListener = clickListener
|
||||
|
@ -90,6 +99,7 @@ class TableBlockHolder(
|
|||
(lm as CustomGridLayoutManager).spanCount = item.rowCount
|
||||
tableEditableCellsAdapter.setTableBlockId(item.id)
|
||||
tableEditableCellsAdapter.updateWithDiffUtil(item.cells)
|
||||
updateCellsSelection(item)
|
||||
} else {
|
||||
(lm as GridLayoutManager).spanCount = item.rowCount
|
||||
tableAdapter.setTableBlockId(item.id)
|
||||
|
@ -102,12 +112,18 @@ class TableBlockHolder(
|
|||
item: BlockView.Table
|
||||
) {
|
||||
payloads.forEach { payload ->
|
||||
if (payload.changes.contains(BlockViewDiffUtil.TABLE_CELLS_CHANGED)) {
|
||||
bind(item)
|
||||
}
|
||||
if (payload.changes.contains(BlockViewDiffUtil.SELECTION_CHANGED)) {
|
||||
selected.isSelected = item.isSelected
|
||||
}
|
||||
if (payload.changes.contains(BlockViewDiffUtil.BACKGROUND_COLOR_CHANGED)) {
|
||||
applyBackground(item.background)
|
||||
}
|
||||
if (payload.changes.contains(BlockViewDiffUtil.TABLE_CELLS_SELECTION_CHANGED)) {
|
||||
updateCellsSelection(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,4 +134,29 @@ class TableBlockHolder(
|
|||
fun recycle() {
|
||||
tableAdapter.submitList(emptyList())
|
||||
}
|
||||
|
||||
private fun updateCellsSelection(item: BlockView.Table) {
|
||||
if (item.selectedCellsIds.isEmpty()) {
|
||||
cellsSelectionState.clear()
|
||||
if (recycler.containsItemDecoration(cellSelectionDecoration)) {
|
||||
recycler.removeItemDecoration(cellSelectionDecoration)
|
||||
}
|
||||
} else {
|
||||
val selectedCells = item.cells.filter { cell ->
|
||||
item.selectedCellsIds.contains(cell.getId())
|
||||
}
|
||||
cellsSelectionState.clear()
|
||||
cellsSelectionState.set(cells = selectedCells)
|
||||
if (cellsSelectionState.current().isNotEmpty()) {
|
||||
cellSelectionDecoration.setSelectionState(cellsSelectionState.current())
|
||||
if (!recycler.containsItemDecoration(cellSelectionDecoration)) {
|
||||
recycler.addItemDecoration(cellSelectionDecoration)
|
||||
} else {
|
||||
recycler.invalidateItemDecorations()
|
||||
}
|
||||
} else {
|
||||
recycler.removeItemDecoration(cellSelectionDecoration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.anytypeio.anytype.core_ui.layout
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.view.children
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class TableCellSelectionDecoration(
|
||||
private val drawable: Drawable
|
||||
) : RecyclerView.ItemDecoration() {
|
||||
|
||||
private val selectionState: MutableList<BlockView.Table.CellSelection> = mutableListOf()
|
||||
|
||||
fun setSelectionState(newState: List<BlockView.Table.CellSelection>) {
|
||||
selectionState.clear()
|
||||
selectionState.addAll(newState)
|
||||
}
|
||||
|
||||
override fun onDraw(
|
||||
canvas: Canvas,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
canvas.save()
|
||||
val rect = Rect()
|
||||
parent.children.forEach { view ->
|
||||
val position = parent.getChildAdapterPosition(view)
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
val cellSelection = selectionState.find { it.cellIndex == position }
|
||||
if (cellSelection != null) {
|
||||
parent.getDecoratedBoundsWithMargins(view, rect)
|
||||
if (cellSelection.left) {
|
||||
drawable.setBounds(
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.left + drawable.intrinsicWidth,
|
||||
rect.bottom
|
||||
)
|
||||
drawable.draw(canvas)
|
||||
}
|
||||
if (cellSelection.top) {
|
||||
val top = rect.top + view.translationY.roundToInt()
|
||||
val bottom = top + drawable.intrinsicHeight
|
||||
drawable.setBounds(
|
||||
rect.left,
|
||||
top,
|
||||
rect.right,
|
||||
bottom
|
||||
)
|
||||
drawable.draw(canvas)
|
||||
}
|
||||
if (cellSelection.right) {
|
||||
val right = rect.right + view.translationX.roundToInt()
|
||||
val left = right - drawable.intrinsicWidth
|
||||
drawable.setBounds(
|
||||
left,
|
||||
rect.top,
|
||||
right,
|
||||
rect.bottom
|
||||
)
|
||||
drawable.draw(canvas)
|
||||
}
|
||||
if (cellSelection.bottom) {
|
||||
val bottom = rect.bottom + view.translationY.roundToInt()
|
||||
val top = bottom - drawable.intrinsicHeight
|
||||
drawable.setBounds(
|
||||
rect.left,
|
||||
top,
|
||||
rect.right,
|
||||
bottom
|
||||
)
|
||||
drawable.draw(canvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
canvas.restore()
|
||||
}
|
||||
}
|
|
@ -1,12 +1,17 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.toolbar
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.animation.doOnEnd
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.WidgetMultiSelectTopToolbarBinding
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
|
||||
class MultiSelectTopToolbarWidget @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
@ -19,4 +24,52 @@ class MultiSelectTopToolbarWidget @JvmOverloads constructor(
|
|||
|
||||
val selectText get() : TextView = binding.tvToolbarTitle
|
||||
val doneButton get() : View = binding.btnDone
|
||||
|
||||
fun setCellSelectionText(count: Int) {
|
||||
when {
|
||||
count == 1 -> {
|
||||
selectText.text = context.getString(R.string.one_selected_cell)
|
||||
}
|
||||
count > 1 -> {
|
||||
selectText.text = context.getString(R.string.number_selected_cells, count)
|
||||
}
|
||||
else -> {
|
||||
selectText.text = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showWithAnimation() {
|
||||
if (translationY < 0) {
|
||||
ObjectAnimator.ofFloat(
|
||||
this,
|
||||
SELECT_BUTTON_ANIMATION_PROPERTY,
|
||||
0f
|
||||
).apply {
|
||||
duration = SELECT_BUTTON_ANIMATION_DURATION
|
||||
interpolator = DecelerateInterpolator()
|
||||
start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hideWithAnimation(action: () -> Unit) {
|
||||
if (translationY >= 0) {
|
||||
ObjectAnimator.ofFloat(
|
||||
this,
|
||||
SELECT_BUTTON_ANIMATION_PROPERTY,
|
||||
-context.dimen(R.dimen.dp_48)
|
||||
).apply {
|
||||
duration = SELECT_BUTTON_ANIMATION_DURATION
|
||||
interpolator = DecelerateInterpolator()
|
||||
doOnEnd { action.invoke() }
|
||||
start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SELECT_BUTTON_ANIMATION_PROPERTY = "translationY"
|
||||
const val SELECT_BUTTON_ANIMATION_DURATION = 200L
|
||||
}
|
||||
}
|
|
@ -6,7 +6,8 @@ import android.view.LayoutInflater
|
|||
import androidx.cardview.widget.CardView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.WidgetSimpleTableBinding
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetItem
|
||||
import com.anytypeio.anytype.presentation.editor.markup.MarkupColorView
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
|
||||
class SimpleTableSettingWidget @JvmOverloads constructor(
|
||||
|
@ -19,12 +20,14 @@ class SimpleTableSettingWidget @JvmOverloads constructor(
|
|||
LayoutInflater.from(context), this, true
|
||||
)
|
||||
|
||||
var onItemClickListener: (SimpleTableWidgetItem) -> Unit = {}
|
||||
|
||||
private val cellAdapter = SimpleTableWidgetAdapter(items = listOf(),
|
||||
onClick = { item -> })
|
||||
onClick = { item -> onItemClickListener.invoke(item)})
|
||||
private val columnAdapter = SimpleTableWidgetAdapter(items = listOf(),
|
||||
onClick = { item -> })
|
||||
onClick = { item -> onItemClickListener.invoke(item)})
|
||||
private val rowAdapter = SimpleTableWidgetAdapter(items = listOf(),
|
||||
onClick = { item -> })
|
||||
onClick = { item -> onItemClickListener.invoke(item)})
|
||||
|
||||
private val pagerAdapter = SimpleTableSettingAdapter(
|
||||
cellAdapter = cellAdapter,
|
||||
|
@ -32,15 +35,18 @@ class SimpleTableSettingWidget @JvmOverloads constructor(
|
|||
rowAdapter = rowAdapter
|
||||
)
|
||||
|
||||
fun onStateChanged(state: SimpleTableWidgetState) {
|
||||
when (state) {
|
||||
is SimpleTableWidgetState.UpdateItems -> {
|
||||
cellAdapter.update(state.cellItems)
|
||||
columnAdapter.update(state.columnItems)
|
||||
rowAdapter.update(state.rowItems)
|
||||
}
|
||||
SimpleTableWidgetState.Idle -> {}
|
||||
}
|
||||
fun onStateChanged(
|
||||
cellItems: List<SimpleTableWidgetItem>,
|
||||
rowItems: List<SimpleTableWidgetItem>,
|
||||
columnItems: List<SimpleTableWidgetItem>
|
||||
) {
|
||||
cellAdapter.update(cellItems)
|
||||
columnAdapter.update(columnItems)
|
||||
rowAdapter.update(rowItems)
|
||||
}
|
||||
|
||||
fun setListener(listener: (SimpleTableWidgetItem) -> Unit = {}) {
|
||||
onItemClickListener = listener
|
||||
}
|
||||
|
||||
init {
|
||||
|
|
|
@ -23,9 +23,11 @@ class SimpleTableWidgetAdapter(
|
|||
val holder = VH(
|
||||
binding = ItemSimpleTableActionBinding.inflate(inflater, parent, false)
|
||||
).apply {
|
||||
val pos = bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION)
|
||||
onClick(items[pos])
|
||||
itemView.setOnClickListener {
|
||||
val pos = bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION)
|
||||
onClick(items[pos])
|
||||
}
|
||||
}
|
||||
return holder
|
||||
}
|
||||
|
|
7
core-ui/src/main/res/drawable/cell_top_border.xml
Normal file
7
core-ui/src/main/res/drawable/cell_top_border.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<size
|
||||
android:width="2dp"
|
||||
android:height="2dp" />
|
||||
<solid android:color="@color/amber_80" />
|
||||
</shape>
|
|
@ -563,6 +563,8 @@
|
|||
<string name="send_email">Send email</string>
|
||||
<string name="call_phone_number">Call phone number</string>
|
||||
<string name="bookmark_icon">Bookmark icon</string>
|
||||
<string name="one_selected_cell">1 cell selected</string>
|
||||
<string name="number_selected_cells">%1$d cells selected</string>
|
||||
|
||||
<string name="error_find_block">Could\'t find the selected block</string>
|
||||
<string name="error_block_selection">Block selection error</string>
|
||||
|
|
|
@ -1101,6 +1101,8 @@ class BlockViewSearchTextTest {
|
|||
val row2Block2 = StubParagraph(id = "$rowId2-$columnId2", text = "bb2")
|
||||
val row2Block3 = StubParagraph(id = "$rowId2-$columnId3", text = "bc3")
|
||||
|
||||
val tableId = MockDataFactory.randomUuid()
|
||||
|
||||
val cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1110,7 +1112,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 0,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1120,7 +1124,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1130,7 +1136,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1140,7 +1148,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 1,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1150,7 +1160,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 3,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1160,7 +1172,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 5,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1170,15 +1184,14 @@ class BlockViewSearchTextTest {
|
|||
BlockView.Table.Column(id = columnId3, background = ThemeColor.DEFAULT)
|
||||
)
|
||||
|
||||
val tableId = MockDataFactory.randomUuid()
|
||||
|
||||
val views = listOf<BlockView>(
|
||||
BlockView.Table(
|
||||
id = tableId,
|
||||
cells = cells,
|
||||
columns = columns,
|
||||
rowCount = 2,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1198,7 +1211,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 0,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1215,7 +1230,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1232,7 +1249,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1249,7 +1268,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 1,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1266,7 +1287,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 3,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1283,7 +1306,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 5,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1306,7 +1331,8 @@ class BlockViewSearchTextTest {
|
|||
cells = expectedCells,
|
||||
columns = columns,
|
||||
rowCount = 2,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1331,6 +1357,8 @@ class BlockViewSearchTextTest {
|
|||
val row2Block2 = StubParagraph(id = "$rowId2-$columnId2", text = "bb2")
|
||||
val row2Block3 = StubParagraph(id = "$rowId2-$columnId3", text = "bc3")
|
||||
|
||||
val tableId = MockDataFactory.randomUuid()
|
||||
|
||||
val cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1340,7 +1368,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 0,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1350,7 +1380,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1360,7 +1392,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1370,7 +1404,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 1,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1380,7 +1416,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 3,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1390,7 +1428,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 5,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1400,15 +1440,14 @@ class BlockViewSearchTextTest {
|
|||
BlockView.Table.Column(id = columnId3, background = ThemeColor.DEFAULT)
|
||||
)
|
||||
|
||||
val tableId = MockDataFactory.randomUuid()
|
||||
|
||||
val views = listOf<BlockView>(
|
||||
BlockView.Table(
|
||||
id = tableId,
|
||||
cells = cells,
|
||||
columns = columns,
|
||||
rowCount = 2,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1421,7 +1460,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 0,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1432,6 +1473,8 @@ class BlockViewSearchTextTest {
|
|||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1442,6 +1485,8 @@ class BlockViewSearchTextTest {
|
|||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1451,7 +1496,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 1,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1461,7 +1508,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 3,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -1471,7 +1520,9 @@ class BlockViewSearchTextTest {
|
|||
rowId = rowId2,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 5,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1496,7 +1547,8 @@ class BlockViewSearchTextTest {
|
|||
cells = expectedCells,
|
||||
columns = columns,
|
||||
rowCount = 2,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -348,7 +348,9 @@ fun StubTwoRowsThreeColumnsSimpleTable(
|
|||
rowId = rowId1,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 0,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -358,7 +360,9 @@ fun StubTwoRowsThreeColumnsSimpleTable(
|
|||
rowId = rowId1,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -368,7 +372,9 @@ fun StubTwoRowsThreeColumnsSimpleTable(
|
|||
rowId = rowId1,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -378,7 +384,9 @@ fun StubTwoRowsThreeColumnsSimpleTable(
|
|||
rowId = rowId2,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 1,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -388,7 +396,9 @@ fun StubTwoRowsThreeColumnsSimpleTable(
|
|||
rowId = rowId2,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 3,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -398,7 +408,9 @@ fun StubTwoRowsThreeColumnsSimpleTable(
|
|||
rowId = rowId2,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 5,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -413,7 +425,8 @@ fun StubTwoRowsThreeColumnsSimpleTable(
|
|||
cells = cells,
|
||||
columns = columns,
|
||||
rowCount = 2,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ class TableBlockTest {
|
|||
val row1Block1 =
|
||||
StubParagraph(id = "$rowId1-$columnId2", text = "a1")
|
||||
val row1Block2 = StubParagraph(id = "$rowId1-$columnId3", text = oldText)
|
||||
val tableId = MockDataFactory.randomUuid()
|
||||
|
||||
val cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
|
@ -67,7 +68,9 @@ class TableBlockTest {
|
|||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 0,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -78,6 +81,8 @@ class TableBlockTest {
|
|||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -88,13 +93,17 @@ class TableBlockTest {
|
|||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId1,
|
||||
columnId = columnId4,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(3),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 6,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -104,7 +113,9 @@ class TableBlockTest {
|
|||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 0,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -114,7 +125,9 @@ class TableBlockTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
block = BlockView.Text.Paragraph(
|
||||
|
@ -124,14 +137,18 @@ class TableBlockTest {
|
|||
rowId = rowId1,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2)
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId1,
|
||||
columnId = columnId4,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(3),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 6,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -148,14 +165,14 @@ class TableBlockTest {
|
|||
}
|
||||
val recycler = givenRecycler(it)
|
||||
|
||||
val tableId = MockDataFactory.randomUuid()
|
||||
val views = listOf<BlockView>(
|
||||
BlockView.Table(
|
||||
id = tableId,
|
||||
cells = cells,
|
||||
columns = columns,
|
||||
rowCount = 1,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
)
|
||||
val adapter = givenAdapter(views)
|
||||
|
@ -186,7 +203,8 @@ class TableBlockTest {
|
|||
cells = cellsNew,
|
||||
columns = columns,
|
||||
rowCount = 1,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -632,6 +632,10 @@ class BlockDataRepository(
|
|||
return remote.objectToSet(ctx, source)
|
||||
}
|
||||
|
||||
override suspend fun clearBlockContent(ctx: Id, blockIds: List<Id>) : Payload {
|
||||
return remote.clearBlockContent(ctx, blockIds)
|
||||
}
|
||||
|
||||
override suspend fun blockDataViewSetSource(
|
||||
ctx: Id,
|
||||
block: Id,
|
||||
|
|
|
@ -258,4 +258,6 @@ interface BlockDataStore {
|
|||
suspend fun objectToSet(ctx: Id, source: List<String>): Id
|
||||
|
||||
suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List<String>): Payload
|
||||
|
||||
suspend fun clearBlockContent(ctx: Id, blockIds: List<Id>) : Payload
|
||||
}
|
|
@ -257,4 +257,6 @@ interface BlockRemote {
|
|||
suspend fun objectToSet(ctx: Id, source: List<String>): Id
|
||||
|
||||
suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List<String>): Payload
|
||||
|
||||
suspend fun clearBlockContent(ctx: Id, blockIds: List<Id>) : Payload
|
||||
}
|
|
@ -555,4 +555,8 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore {
|
|||
): Payload {
|
||||
return remote.blockDataViewSetSource(ctx, block, sources)
|
||||
}
|
||||
|
||||
override suspend fun clearBlockContent(ctx: Id, blockIds: List<Id>): Payload {
|
||||
return remote.clearBlockContent(ctx, blockIds)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.anytypeio.anytype.domain.block.interactor
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
||||
class ClearBlockContent(
|
||||
private val repository: BlockRepository,
|
||||
) : BaseUseCase<Payload, ClearBlockContent.Params>() {
|
||||
|
||||
data class Params(
|
||||
val ctx: Id,
|
||||
val blockIds: List<Id>
|
||||
)
|
||||
|
||||
override suspend fun run(params: Params): Either<Throwable, Payload> = safe {
|
||||
repository.clearBlockContent(
|
||||
ctx = params.ctx,
|
||||
blockIds = params.blockIds
|
||||
)
|
||||
}
|
||||
}
|
|
@ -323,4 +323,6 @@ interface BlockRepository {
|
|||
suspend fun objectToSet(ctx: Id, source: List<String>): Id
|
||||
|
||||
suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List<String>): Payload
|
||||
|
||||
suspend fun clearBlockContent(ctx: Id, blockIds: List<Id>) : Payload
|
||||
}
|
|
@ -594,4 +594,8 @@ class BlockMiddleware(
|
|||
): Payload {
|
||||
return middleware.blockDataViewSetSource(ctx, block, sources)
|
||||
}
|
||||
|
||||
override suspend fun clearBlockContent(ctx: Id, blockIds: List<Id>): Payload {
|
||||
return middleware.clearBlockContent(ctx, blockIds)
|
||||
}
|
||||
}
|
|
@ -1756,6 +1756,21 @@ class Middleware(
|
|||
return response.event.toPayload()
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun clearBlockContent(
|
||||
ctx: Id,
|
||||
blockIds: List<Id>
|
||||
): Payload {
|
||||
val request = Rpc.BlockText.ListClearContent.Request(
|
||||
contextId = ctx,
|
||||
blockIds = blockIds
|
||||
)
|
||||
if (BuildConfig.DEBUG) logRequest(request)
|
||||
val response = service.blockListClearContent(request)
|
||||
if (BuildConfig.DEBUG) logResponse(response)
|
||||
return response.event.toPayload()
|
||||
}
|
||||
|
||||
private fun logRequest(any: Any) {
|
||||
val message = "===> " + any::class.java.canonicalName + ":" + "\n" + any.toString()
|
||||
Timber.d(message)
|
||||
|
|
|
@ -236,6 +236,10 @@ interface MiddlewareService {
|
|||
@Throws(Exception::class)
|
||||
fun blockRelationSetKey(request: Rpc.BlockRelation.SetKey.Request): Rpc.BlockRelation.SetKey.Response
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun blockListClearContent(request: Rpc.BlockText.ListClearContent.Request)
|
||||
: Rpc.BlockText.ListClearContent.Response
|
||||
|
||||
//endregion
|
||||
|
||||
//region NAVIGATION commands
|
||||
|
|
|
@ -438,6 +438,19 @@ class MiddlewareServiceImplementation : MiddlewareService {
|
|||
}
|
||||
}
|
||||
|
||||
override fun blockListClearContent(request: Rpc.BlockText.ListClearContent.Request): Rpc.BlockText.ListClearContent.Response {
|
||||
val encoded = Service.blockTextListClearContent(
|
||||
Rpc.BlockText.ListClearContent.Request.ADAPTER.encode(request)
|
||||
)
|
||||
val response = Rpc.BlockText.ListClearContent.Response.ADAPTER.decode(encoded)
|
||||
val error = response.error
|
||||
if (error != null && error.code != Rpc.BlockText.ListClearContent.Response.Error.Code.NULL) {
|
||||
throw Exception(error.description)
|
||||
} else {
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
override fun blockSplit(request: Rpc.Block.Split.Request): Rpc.Block.Split.Response {
|
||||
val encoded = Service.blockSplit(Rpc.Block.Split.Request.ADAPTER.encode(request))
|
||||
val response = Rpc.Block.Split.Response.ADAPTER.decode(encoded)
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.anytypeio.anytype.presentation.editor
|
|||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Block.Content.Text.Style
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.TextBlock
|
||||
import com.anytypeio.anytype.presentation.common.StateReducer
|
||||
import com.anytypeio.anytype.presentation.editor.ControlPanelMachine.Event
|
||||
|
@ -10,9 +11,11 @@ import com.anytypeio.anytype.presentation.editor.ControlPanelMachine.Reducer
|
|||
import com.anytypeio.anytype.presentation.editor.editor.control.ControlPanelState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.control.ControlPanelState.Companion.init
|
||||
import com.anytypeio.anytype.presentation.editor.editor.control.ControlPanelState.Toolbar
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashWidgetState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.styling.StyleToolbarState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.styling.getSupportedMarkupTypes
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetItem
|
||||
import com.anytypeio.anytype.presentation.extension.style
|
||||
import com.anytypeio.anytype.presentation.navigation.DefaultObjectView
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeView
|
||||
|
@ -212,6 +215,18 @@ sealed class ControlPanelMachine {
|
|||
data class Show(val data: List<ObjectTypeView>) : ObjectTypesWidgetEvent()
|
||||
object Hide : ObjectTypesWidgetEvent()
|
||||
}
|
||||
|
||||
sealed class SimpleTableWidget : Event() {
|
||||
data class Show(
|
||||
val tableId: Id,
|
||||
val cells: List<BlockView.Table.Cell>,
|
||||
val cellItems: List<SimpleTableWidgetItem> = emptyList(),
|
||||
val rowItems: List<SimpleTableWidgetItem> = emptyList(),
|
||||
val columnItems: List<SimpleTableWidgetItem> = emptyList()
|
||||
) : SimpleTableWidget()
|
||||
|
||||
data class Hide(val tableId: Id) : SimpleTableWidget()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -374,7 +389,8 @@ sealed class ControlPanelMachine {
|
|||
),
|
||||
slashWidget = Toolbar.SlashWidget.reset(),
|
||||
objectTypesToolbar = Toolbar.ObjectTypes.reset(),
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset()
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset(),
|
||||
simpleTableWidget = Toolbar.SimpleTableWidget.reset()
|
||||
)
|
||||
} else {
|
||||
state.copy(
|
||||
|
@ -434,7 +450,7 @@ sealed class ControlPanelMachine {
|
|||
!state.mainToolbar.isVisible -> state.copy(
|
||||
mainToolbar = state.mainToolbar.copy(
|
||||
isVisible = true,
|
||||
targetBlockType = when(event.style) {
|
||||
targetBlockType = when (event.style) {
|
||||
Style.TITLE -> Toolbar.Main.TargetBlockType.Title
|
||||
else -> Toolbar.Main.TargetBlockType.Any
|
||||
}
|
||||
|
@ -446,12 +462,13 @@ sealed class ControlPanelMachine {
|
|||
navigationToolbar = Toolbar.Navigation(
|
||||
isVisible = false
|
||||
),
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset()
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset(),
|
||||
simpleTableWidget = Toolbar.SimpleTableWidget.reset()
|
||||
)
|
||||
else -> {
|
||||
state.copy(
|
||||
mainToolbar = state.mainToolbar.copy(
|
||||
targetBlockType = when(event.style) {
|
||||
targetBlockType = when (event.style) {
|
||||
Style.TITLE -> Toolbar.Main.TargetBlockType.Title
|
||||
else -> Toolbar.Main.TargetBlockType.Any
|
||||
}
|
||||
|
@ -462,7 +479,8 @@ sealed class ControlPanelMachine {
|
|||
mentionToolbar = Toolbar.MentionToolbar.reset(),
|
||||
slashWidget = Toolbar.SlashWidget.reset(),
|
||||
objectTypesToolbar = Toolbar.ObjectTypes.reset(),
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset()
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset(),
|
||||
simpleTableWidget = Toolbar.SimpleTableWidget.reset()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -495,6 +513,9 @@ sealed class ControlPanelMachine {
|
|||
)
|
||||
)
|
||||
}
|
||||
is Event.SimpleTableWidget -> {
|
||||
handleSimpleTableEvent(event, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleStylingToolbarEvent(
|
||||
|
@ -722,7 +743,8 @@ sealed class ControlPanelMachine {
|
|||
isVisible = false
|
||||
),
|
||||
slashWidget = Toolbar.SlashWidget.reset(),
|
||||
mentionToolbar = Toolbar.MentionToolbar.reset()
|
||||
mentionToolbar = Toolbar.MentionToolbar.reset(),
|
||||
simpleTableWidget = Toolbar.SimpleTableWidget.reset()
|
||||
)
|
||||
is Event.MultiSelect.OnExit -> state.copy(
|
||||
multiSelect = state.multiSelect.copy(
|
||||
|
@ -774,7 +796,8 @@ sealed class ControlPanelMachine {
|
|||
styleTextToolbar = Toolbar.Styling.reset(),
|
||||
mentionToolbar = Toolbar.MentionToolbar.reset(),
|
||||
slashWidget = Toolbar.SlashWidget.reset(),
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset()
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset(),
|
||||
simpleTableWidget = Toolbar.SimpleTableWidget.reset()
|
||||
)
|
||||
}
|
||||
Event.ReadMode.OnExit -> state.copy()
|
||||
|
@ -865,6 +888,55 @@ sealed class ControlPanelMachine {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleSimpleTableEvent(
|
||||
event: Event.SimpleTableWidget,
|
||||
state: ControlPanelState
|
||||
): ControlPanelState = when (event) {
|
||||
is Event.SimpleTableWidget.Show -> {
|
||||
state.copy(
|
||||
simpleTableWidget = state.simpleTableWidget.copy(
|
||||
isVisible = true,
|
||||
tableId = event.tableId,
|
||||
cells = event.cells,
|
||||
cellItems = event.cellItems,
|
||||
rowItems = event.rowItems,
|
||||
columnItems = event.columnItems
|
||||
),
|
||||
cellsSelectTopWidget = state.cellsSelectTopWidget.copy(
|
||||
isVisible = true,
|
||||
count = event.cells.size
|
||||
),
|
||||
mainToolbar = Toolbar.Main.reset(),
|
||||
styleColorBackgroundToolbar = Toolbar.Styling.ColorBackground.reset(),
|
||||
styleExtraToolbar = Toolbar.Styling.Extra.reset(),
|
||||
styleTextToolbar = Toolbar.Styling.reset(),
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset(),
|
||||
navigationToolbar = Toolbar.Navigation.reset(),
|
||||
slashWidget = Toolbar.SlashWidget.reset(),
|
||||
mentionToolbar = Toolbar.MentionToolbar.reset(),
|
||||
multiSelect = Toolbar.MultiSelect.reset()
|
||||
)
|
||||
}
|
||||
is Event.SimpleTableWidget.Hide -> {
|
||||
state.copy(
|
||||
navigationToolbar = state.navigationToolbar.copy(
|
||||
isVisible = true
|
||||
),
|
||||
multiSelect = Toolbar.MultiSelect.reset(),
|
||||
mainToolbar = Toolbar.Main.reset(),
|
||||
styleColorBackgroundToolbar = Toolbar.Styling.ColorBackground.reset(),
|
||||
styleExtraToolbar = Toolbar.Styling.Extra.reset(),
|
||||
styleTextToolbar = Toolbar.Styling.reset(),
|
||||
styleBackgroundToolbar = Toolbar.Styling.Background.reset(),
|
||||
simpleTableWidget = state.simpleTableWidget.copy(
|
||||
isVisible = false,
|
||||
tableId = event.tableId
|
||||
),
|
||||
cellsSelectTopWidget = Toolbar.CellSelection.reset()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun logState(text: String, state: ControlPanelState) {
|
||||
Timber.i(
|
||||
"REDUCER, $text STATE:${
|
||||
|
|
|
@ -75,6 +75,11 @@ interface Editor {
|
|||
*/
|
||||
data class Multi(val targets: Set<Id>) : Styling()
|
||||
}
|
||||
|
||||
/**
|
||||
* Editor in simple table menu mode.
|
||||
*/
|
||||
data class Table(val tableId: Id) : Mode()
|
||||
}
|
||||
|
||||
class Storage {
|
||||
|
|
|
@ -140,10 +140,7 @@ import com.anytypeio.anytype.presentation.editor.editor.styling.getStyleBackgrou
|
|||
import com.anytypeio.anytype.presentation.editor.editor.styling.getStyleColorBackgroundToolbarState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.styling.getStyleOtherToolbarState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.styling.getStyleTextToolbarState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetEvent
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetViewState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetItem
|
||||
import com.anytypeio.anytype.presentation.editor.editor.toCoreModel
|
||||
import com.anytypeio.anytype.presentation.editor.editor.updateText
|
||||
import com.anytypeio.anytype.presentation.editor.model.EditorFooter
|
||||
|
@ -153,6 +150,9 @@ import com.anytypeio.anytype.presentation.editor.render.BlockViewRenderer
|
|||
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
|
||||
import com.anytypeio.anytype.presentation.editor.search.search
|
||||
import com.anytypeio.anytype.presentation.editor.selection.SelectionStateHolder
|
||||
import com.anytypeio.anytype.presentation.editor.selection.getSimpleTableWidgetItems
|
||||
import com.anytypeio.anytype.presentation.editor.selection.toggleTableMode
|
||||
import com.anytypeio.anytype.presentation.editor.selection.updateTableBlockSelection
|
||||
import com.anytypeio.anytype.presentation.editor.template.EditorTemplateDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.template.SelectTemplateEvent
|
||||
import com.anytypeio.anytype.presentation.editor.template.SelectTemplateState
|
||||
|
@ -248,7 +248,6 @@ class EditorViewModel(
|
|||
private val setDocCoverImage: SetDocCoverImage,
|
||||
private val setDocImageIcon: SetDocumentImageIcon,
|
||||
private val templateDelegate: EditorTemplateDelegate,
|
||||
private val simpleTableDelegate: SimpleTableDelegate,
|
||||
private val createNewObject: CreateNewObject,
|
||||
private val objectToSet: ConvertObjectToSet
|
||||
) : ViewStateViewModel<ViewState>(),
|
||||
|
@ -259,7 +258,6 @@ class EditorViewModel(
|
|||
ToggleStateHolder by renderer,
|
||||
SelectionStateHolder by orchestrator.memory.selections,
|
||||
EditorTemplateDelegate by templateDelegate,
|
||||
SimpleTableDelegate by simpleTableDelegate,
|
||||
StateReducer<List<Block>, Event> by reducer {
|
||||
|
||||
val actions = MutableStateFlow(ActionItemType.defaultSorting)
|
||||
|
@ -282,17 +280,6 @@ class EditorViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
val simpleTablesViewState = simpleTableDelegateState.map { state ->
|
||||
when (state) {
|
||||
is SimpleTableWidgetState.UpdateItems -> {
|
||||
SimpleTableWidgetViewState.Active(
|
||||
state = state
|
||||
)
|
||||
}
|
||||
SimpleTableWidgetState.Idle -> SimpleTableWidgetViewState.Idle
|
||||
}
|
||||
}
|
||||
|
||||
val searchResultScrollPosition = MutableStateFlow(NO_SEARCH_RESULT_POSITION)
|
||||
|
||||
private val session = MutableStateFlow(Session.IDLE)
|
||||
|
@ -2444,7 +2431,7 @@ class EditorViewModel(
|
|||
if (view == null) {
|
||||
val cell = views.findTableCellView(target)
|
||||
if (cell != null) {
|
||||
onShowSimpleTableWidgetClicked(target)
|
||||
proceedWithEnterTableMode(cell)
|
||||
viewModelScope.sendAnalyticsSelectionMenuEvent(analytics)
|
||||
}
|
||||
} else {
|
||||
|
@ -3842,13 +3829,13 @@ class EditorViewModel(
|
|||
return
|
||||
}
|
||||
proceedWithSelectingCell(
|
||||
cellId = clicked.cellId,
|
||||
tableId = clicked.tableId
|
||||
cellId = clicked.cell.getId(),
|
||||
tableId = clicked.cell.tableId
|
||||
)
|
||||
onTableRowEmptyCellClicked(
|
||||
cellId = clicked.cellId,
|
||||
rowId = clicked.rowId,
|
||||
tableId = clicked.tableId
|
||||
cellId = clicked.cell.getId(),
|
||||
rowId = clicked.cell.rowId,
|
||||
tableId = clicked.cell.tableId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -3860,16 +3847,28 @@ class EditorViewModel(
|
|||
}
|
||||
}
|
||||
proceedWithSelectingCell(
|
||||
cellId = clicked.cellId,
|
||||
tableId = clicked.tableId
|
||||
cellId = clicked.cell.getId(),
|
||||
tableId = clicked.cell.tableId
|
||||
)
|
||||
onTableRowEmptyCellClicked(
|
||||
cellId = clicked.cellId,
|
||||
rowId = clicked.rowId,
|
||||
tableId = clicked.tableId
|
||||
cellId = clicked.cell.getId(),
|
||||
rowId = clicked.cell.rowId,
|
||||
tableId = clicked.cell.tableId
|
||||
)
|
||||
}
|
||||
EditorMode.Select -> onBlockMultiSelectClicked(target = clicked.tableId)
|
||||
EditorMode.Select -> onBlockMultiSelectClicked(target = clicked.cell.tableId)
|
||||
is EditorMode.Table -> {
|
||||
val modeTableId = (mode as EditorMode.Table).tableId
|
||||
val cellTableId = clicked.cell.tableId
|
||||
if (cellTableId == modeTableId) {
|
||||
proceedWithClickingOnCellInTableMode(
|
||||
cell = clicked.cell,
|
||||
tableId = cellTableId
|
||||
)
|
||||
} else {
|
||||
Timber.e("Cell is from the different table, amend click")
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
@ -3881,15 +3880,15 @@ class EditorViewModel(
|
|||
return
|
||||
}
|
||||
proceedWithSelectingCell(
|
||||
cellId = clicked.cellId,
|
||||
tableId = clicked.tableId
|
||||
cellId = clicked.cell.getId(),
|
||||
tableId = clicked.cell.tableId
|
||||
)
|
||||
if (!BuildConfig.USE_SIMPLE_TABLES_IN_EDITOR_EDDITING) {
|
||||
dispatch(
|
||||
Command.OpenSetBlockTextValueScreen(
|
||||
ctx = context,
|
||||
block = clicked.cellId,
|
||||
table = clicked.tableId
|
||||
block = clicked.cell.getId(),
|
||||
table = clicked.cell.tableId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -3901,26 +3900,34 @@ class EditorViewModel(
|
|||
}
|
||||
if (!BuildConfig.USE_SIMPLE_TABLES_IN_EDITOR_EDDITING) {
|
||||
proceedWithSelectingCell(
|
||||
cellId = clicked.cellId,
|
||||
tableId = clicked.tableId
|
||||
cellId = clicked.cell.getId(),
|
||||
tableId = clicked.cell.tableId
|
||||
)
|
||||
dispatch(
|
||||
Command.OpenSetBlockTextValueScreen(
|
||||
ctx = context,
|
||||
block = clicked.cellId,
|
||||
table = clicked.tableId
|
||||
block = clicked.cell.getId(),
|
||||
table = clicked.cell.tableId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
EditorMode.Select -> onBlockMultiSelectClicked(target = clicked.tableId)
|
||||
EditorMode.Select -> onBlockMultiSelectClicked(target = clicked.cell.tableId)
|
||||
is EditorMode.Table -> {
|
||||
val modeTableId = (mode as EditorMode.Table).tableId
|
||||
val cellTableId = clicked.cell.tableId
|
||||
if (cellTableId == modeTableId) {
|
||||
proceedWithClickingOnCellInTableMode(
|
||||
cell = clicked.cell,
|
||||
tableId = cellTableId
|
||||
)
|
||||
} else {
|
||||
Timber.e("Cell is from the different table, amend click")
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
is ListenerType.TableEmptyCellMenu -> {}
|
||||
is ListenerType.TableTextCellMenu -> {
|
||||
onShowSimpleTableWidgetClicked(id = clicked.cellId)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
@ -6111,13 +6118,121 @@ class EditorViewModel(
|
|||
//endregion
|
||||
|
||||
//region SIMPLE TABLES
|
||||
private fun onShowSimpleTableWidgetClicked(id: Id) {
|
||||
viewModelScope.launch {
|
||||
onSimpleTableEvent(SimpleTableWidgetEvent.onStart(id = id))
|
||||
fun onCellsSelectionDoneClick() {
|
||||
proceedWithExitingTableMode()
|
||||
}
|
||||
|
||||
fun onHideSimpleTableWidget() {
|
||||
proceedWithExitingTableMode()
|
||||
}
|
||||
|
||||
fun onSimpleTableWidgetItemClicked(item: SimpleTableWidgetItem) {
|
||||
when (item) {
|
||||
SimpleTableWidgetItem.Cell.ClearContents -> {
|
||||
val selected = currentSelection()
|
||||
viewModelScope.launch {
|
||||
orchestrator.proxies.intents.send(
|
||||
Intent.Text.ClearContent(
|
||||
context = context,
|
||||
targets = selected.toList()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
fun onHideSimpleTableWidget() {}
|
||||
/**
|
||||
* Enter EditorMode.Table
|
||||
*/
|
||||
private fun proceedWithEnterTableMode(cell: BlockView.Table.Cell) {
|
||||
viewModelScope.launch {
|
||||
mode = EditorMode.Table(tableId = cell.tableId)
|
||||
clearSelections()
|
||||
toggleSelection(target = cell.getId())
|
||||
|
||||
orchestrator.stores.focus.update(Editor.Focus.empty())
|
||||
orchestrator.stores.views.update(
|
||||
views.toggleTableMode(
|
||||
cellsMode = BlockView.Mode.READ,
|
||||
selectedCellsIds = currentSelection().toList()
|
||||
)
|
||||
)
|
||||
renderCommand.send(Unit)
|
||||
controlPanelInteractor.onEvent(
|
||||
ControlPanelMachine.Event.SimpleTableWidget.Show(
|
||||
cellItems = listOf(cell).getSimpleTableWidgetItems(),
|
||||
rowItems = emptyList(),
|
||||
columnItems = emptyList(),
|
||||
cells = listOf(cell),
|
||||
tableId = cell.tableId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit EditorMode.Table
|
||||
*/
|
||||
private fun proceedWithExitingTableMode() {
|
||||
Timber.d("proceedWithExitingTableMode, mode:[$mode]")
|
||||
if (currentSelection().isNotEmpty()) clearSelections()
|
||||
val currentMode = mode
|
||||
if (currentMode is EditorMode.Table) {
|
||||
val tableId = currentMode.tableId
|
||||
mode = EditorMode.Edit
|
||||
controlPanelInteractor.onEvent(
|
||||
ControlPanelMachine.Event.SimpleTableWidget.Hide(
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
viewModelScope.launch {
|
||||
orchestrator.stores.views.update(
|
||||
views.toggleTableMode(
|
||||
cellsMode = BlockView.Mode.EDIT,
|
||||
selectedCellsIds = currentSelection().toList()
|
||||
)
|
||||
)
|
||||
renderCommand.send(Unit)
|
||||
}
|
||||
} else {
|
||||
Timber.w("Can't exit Mode.Table, current mode is $mode")
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithClickingOnCellInTableMode(
|
||||
tableId: Id,
|
||||
cell: BlockView.Table.Cell
|
||||
) {
|
||||
toggleSelection(target = cell.getId())
|
||||
if (currentSelection().isEmpty()) {
|
||||
proceedWithExitingTableMode()
|
||||
} else {
|
||||
val tableBlock = views.find { it.id == tableId } as BlockView.Table
|
||||
val selectedCells = tableBlock.cells.mapNotNull {
|
||||
if (currentSelection().contains(it.getId())) it else null
|
||||
}
|
||||
viewModelScope.launch {
|
||||
orchestrator.stores.views.update(
|
||||
views.updateTableBlockSelection(
|
||||
tableId = tableBlock.id,
|
||||
selection = currentSelection().toList()
|
||||
)
|
||||
)
|
||||
renderCommand.send(Unit)
|
||||
}
|
||||
controlPanelInteractor.onEvent(
|
||||
ControlPanelMachine.Event.SimpleTableWidget.Show(
|
||||
cellItems = listOf(cell).getSimpleTableWidgetItems(),
|
||||
rowItems = emptyList(),
|
||||
columnItems = emptyList(),
|
||||
cells = selectedCells,
|
||||
tableId = cell.tableId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithSelectingCell(cellId: Id, tableId: Id) {
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ import com.anytypeio.anytype.presentation.common.Delegator
|
|||
import com.anytypeio.anytype.presentation.common.StateReducer
|
||||
import com.anytypeio.anytype.presentation.editor.editor.DetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.editor.editor.Orchestrator
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
|
||||
import com.anytypeio.anytype.presentation.editor.template.EditorTemplateDelegate
|
||||
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
|
||||
|
@ -69,7 +68,6 @@ open class EditorViewModelFactory(
|
|||
private val setDocCoverImage: SetDocCoverImage,
|
||||
private val setDocImageIcon: SetDocumentImageIcon,
|
||||
private val editorTemplateDelegate: EditorTemplateDelegate,
|
||||
private val simpleTablesDelegate: SimpleTableDelegate,
|
||||
private val createNewObject: CreateNewObject,
|
||||
private val objectToSet: ConvertObjectToSet
|
||||
) : ViewModelProvider.Factory {
|
||||
|
@ -107,7 +105,6 @@ open class EditorViewModelFactory(
|
|||
setDocImageIcon = setDocImageIcon,
|
||||
templateDelegate = editorTemplateDelegate,
|
||||
createNewObject = createNewObject,
|
||||
simpleTableDelegate = simpleTablesDelegate,
|
||||
objectToSet = objectToSet
|
||||
) as T
|
||||
}
|
||||
|
|
|
@ -169,6 +169,11 @@ sealed class Intent {
|
|||
val targets: List<Id>,
|
||||
val mark: Block.Content.Text.Mark
|
||||
) : Text()
|
||||
|
||||
class ClearContent(
|
||||
val context: Id,
|
||||
val targets: List<Id>
|
||||
): Text()
|
||||
}
|
||||
|
||||
sealed class Media : Intent() {
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.anytypeio.anytype.analytics.event.EventAnalytics
|
|||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.domain.base.suspendFold
|
||||
import com.anytypeio.anytype.domain.block.UpdateDivider
|
||||
import com.anytypeio.anytype.domain.block.interactor.ClearBlockContent
|
||||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.DuplicateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.MergeBlocks
|
||||
|
@ -88,7 +89,8 @@ class Orchestrator(
|
|||
val stores: Editor.Storage,
|
||||
val proxies: Editor.Proxer,
|
||||
val textInteractor: Interactor.TextInteractor,
|
||||
private val analytics: Analytics
|
||||
private val analytics: Analytics,
|
||||
private val clearBlockContent: ClearBlockContent
|
||||
) {
|
||||
|
||||
private val defaultOnError: suspend (Throwable) -> Unit = { Timber.e(it) }
|
||||
|
@ -627,6 +629,17 @@ class Orchestrator(
|
|||
success = { payload -> proxies.payloads.send(payload) }
|
||||
)
|
||||
}
|
||||
is Intent.Text.ClearContent -> {
|
||||
clearBlockContent(
|
||||
params = ClearBlockContent.Params(
|
||||
ctx = intent.context,
|
||||
blockIds = intent.targets
|
||||
)
|
||||
).process(
|
||||
failure = defaultOnError,
|
||||
success = { payload -> proxies.payloads.send(payload) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package com.anytypeio.anytype.presentation.editor.editor.control
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.presentation.editor.editor.Markup
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashWidgetState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.styling.StyleToolbarState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetItem
|
||||
import com.anytypeio.anytype.presentation.editor.markup.MarkupStyleDescriptor
|
||||
import com.anytypeio.anytype.presentation.navigation.DefaultObjectView
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeView
|
||||
|
@ -26,7 +29,9 @@ data class ControlPanelState(
|
|||
val mentionToolbar: Toolbar.MentionToolbar = Toolbar.MentionToolbar.reset(),
|
||||
val slashWidget: Toolbar.SlashWidget = Toolbar.SlashWidget.reset(),
|
||||
val searchToolbar: Toolbar.SearchToolbar = Toolbar.SearchToolbar.reset(),
|
||||
val objectTypesToolbar: Toolbar.ObjectTypes = Toolbar.ObjectTypes.reset()
|
||||
val objectTypesToolbar: Toolbar.ObjectTypes = Toolbar.ObjectTypes.reset(),
|
||||
val simpleTableWidget: Toolbar.SimpleTableWidget = Toolbar.SimpleTableWidget.reset(),
|
||||
val cellsSelectTopWidget: Toolbar.CellSelection = Toolbar.CellSelection.reset()
|
||||
) {
|
||||
|
||||
sealed class Toolbar {
|
||||
|
@ -251,6 +256,38 @@ data class ControlPanelState(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class SimpleTableWidget(
|
||||
override val isVisible: Boolean,
|
||||
val tableId: Id,
|
||||
val cells: List<BlockView.Table.Cell>,
|
||||
val cellItems: List<SimpleTableWidgetItem> = emptyList(),
|
||||
val rowItems: List<SimpleTableWidgetItem> = emptyList(),
|
||||
val columnItems: List<SimpleTableWidgetItem> = emptyList()
|
||||
) : Toolbar() {
|
||||
companion object {
|
||||
fun reset(): SimpleTableWidget = SimpleTableWidget(
|
||||
isVisible = false,
|
||||
tableId = "",
|
||||
cells = emptyList(),
|
||||
cellItems = emptyList(),
|
||||
rowItems = emptyList(),
|
||||
columnItems = emptyList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class CellSelection(
|
||||
override val isVisible: Boolean,
|
||||
val count: Int
|
||||
) : Toolbar() {
|
||||
companion object {
|
||||
fun reset(): CellSelection = CellSelection(
|
||||
isVisible = false,
|
||||
count = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -300,7 +337,9 @@ data class ControlPanelState(
|
|||
isVisible = false
|
||||
),
|
||||
slashWidget = Toolbar.SlashWidget.reset(),
|
||||
objectTypesToolbar = Toolbar.ObjectTypes.reset()
|
||||
objectTypesToolbar = Toolbar.ObjectTypes.reset(),
|
||||
simpleTableWidget = Toolbar.SimpleTableWidget.reset(),
|
||||
cellsSelectTopWidget = Toolbar.CellSelection.reset()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -72,8 +72,6 @@ sealed interface ListenerType {
|
|||
|
||||
data class TableOfContentsItem(val target: Id, val item: Id) : ListenerType
|
||||
data class TableOfContents(val target: Id) : ListenerType
|
||||
data class TableEmptyCell(val cellId: Id, val rowId: Id, val tableId: Id) : ListenerType
|
||||
data class TableTextCell(val cellId: Id, val tableId: Id) : ListenerType
|
||||
data class TableEmptyCellMenu(val rowId: Id, val columnId: Id) : ListenerType
|
||||
data class TableTextCellMenu(val cellId: Id, val rowId: Id, val tableId: Id) : ListenerType
|
||||
data class TableEmptyCell(val cell: BlockView.Table.Cell) : ListenerType
|
||||
data class TableTextCell(val cell: BlockView.Table.Cell) : ListenerType
|
||||
}
|
|
@ -192,6 +192,7 @@ sealed class BlockView : ViewType {
|
|||
object H2 : Header()
|
||||
object H3 : Header()
|
||||
}
|
||||
|
||||
object Code : Style()
|
||||
object Card : Style()
|
||||
}
|
||||
|
@ -739,7 +740,8 @@ sealed class BlockView : ViewType {
|
|||
override val indent: Int = 0,
|
||||
override val decorations: List<Decoration> = emptyList(),
|
||||
val lang: String? = null
|
||||
) : BlockView(), Permission, Selectable, Focusable, Cursor, Indentable, TextSupport, Decoratable {
|
||||
) : BlockView(), Permission, Selectable, Focusable, Cursor, Indentable, TextSupport,
|
||||
Decoratable {
|
||||
override fun getViewType() = HOLDER_CODE_SNIPPET
|
||||
}
|
||||
|
||||
|
@ -1090,7 +1092,7 @@ sealed class BlockView : ViewType {
|
|||
override fun getViewType() = HOLDER_OBJECT_LINK_DEFAULT
|
||||
}
|
||||
|
||||
sealed class Card: Default() {
|
||||
sealed class Card : Default() {
|
||||
|
||||
abstract val isPreviousBlockMedia: Boolean
|
||||
|
||||
|
@ -1138,7 +1140,7 @@ sealed class BlockView : ViewType {
|
|||
override val decorations: List<Decoration> = emptyList(),
|
||||
override val objectTypeName: String? = null,
|
||||
override val isPreviousBlockMedia: Boolean,
|
||||
val cover : Cover?
|
||||
val cover: Cover?
|
||||
) : Card() {
|
||||
override fun getViewType() = HOLDER_OBJECT_LINK_CARD_SMALL_ICON_COVER
|
||||
}
|
||||
|
@ -1155,7 +1157,7 @@ sealed class BlockView : ViewType {
|
|||
override val decorations: List<Decoration> = emptyList(),
|
||||
override val objectTypeName: String? = null,
|
||||
override val isPreviousBlockMedia: Boolean,
|
||||
val cover : Cover?
|
||||
val cover: Cover?
|
||||
) : Card() {
|
||||
override fun getViewType() = HOLDER_OBJECT_LINK_CARD_MEDIUM_ICON_COVER
|
||||
}
|
||||
|
@ -1239,7 +1241,7 @@ sealed class BlockView : ViewType {
|
|||
data class FeaturedRelation(
|
||||
override val id: String,
|
||||
val relations: List<DocumentRelationView>,
|
||||
val allowChangingObjectType : Boolean = true
|
||||
val allowChangingObjectType: Boolean = true
|
||||
) : BlockView() {
|
||||
override fun getViewType(): Int = HOLDER_FEATURED_RELATION
|
||||
}
|
||||
|
@ -1320,7 +1322,8 @@ sealed class BlockView : ViewType {
|
|||
val background: ThemeColor = ThemeColor.DEFAULT,
|
||||
val columns: List<Column>,
|
||||
val cells: List<Cell>,
|
||||
val rowCount: Int
|
||||
val rowCount: Int,
|
||||
val selectedCellsIds: List<Id>
|
||||
) : BlockView(), Selectable {
|
||||
override fun getViewType(): Int = HOLDER_TABLE
|
||||
|
||||
|
@ -1332,13 +1335,27 @@ sealed class BlockView : ViewType {
|
|||
val columnId: Id,
|
||||
val columnIndex: ColumnIndex,
|
||||
val isHeader: Boolean = false,
|
||||
val block: Text.Paragraph?
|
||||
val block: Text.Paragraph?,
|
||||
val tableId: Id,
|
||||
val cellIndex: Int
|
||||
) {
|
||||
fun getId() = "$rowId-$columnId"
|
||||
}
|
||||
|
||||
data class CellSelection(
|
||||
val cellId: String,
|
||||
val rowIndex: RowIndex,
|
||||
val columnIndex: ColumnIndex,
|
||||
var left: Boolean,
|
||||
var top: Boolean,
|
||||
var right: Boolean,
|
||||
var bottom: Boolean,
|
||||
var cellIndex: Int
|
||||
)
|
||||
|
||||
@JvmInline
|
||||
value class RowIndex(val value: Int)
|
||||
|
||||
@JvmInline
|
||||
value class ColumnIndex(val value: Int)
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.editor.editor.table
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.scan
|
||||
import timber.log.Timber
|
||||
|
||||
interface SimpleTableDelegate {
|
||||
val simpleTableDelegateState: Flow<SimpleTableWidgetState>
|
||||
suspend fun onSimpleTableEvent(event: SimpleTableWidgetEvent)
|
||||
}
|
||||
|
||||
class DefaultSimpleTableDelegate : SimpleTableDelegate {
|
||||
|
||||
private val events = MutableSharedFlow<SimpleTableWidgetEvent>(replay = 0)
|
||||
|
||||
override val simpleTableDelegateState =
|
||||
events.scan(SimpleTableWidgetState.init()) { state, event ->
|
||||
when (event) {
|
||||
is SimpleTableWidgetEvent.onStart -> {
|
||||
SimpleTableWidgetState.UpdateItems(
|
||||
cellItems = listOf(
|
||||
SimpleTableWidgetItem.Cell.ClearContents,
|
||||
SimpleTableWidgetItem.Cell.Style,
|
||||
SimpleTableWidgetItem.Cell.Color,
|
||||
SimpleTableWidgetItem.Cell.ClearStyle
|
||||
),
|
||||
rowItems = listOf(
|
||||
SimpleTableWidgetItem.Row.ClearContents,
|
||||
SimpleTableWidgetItem.Row.Color,
|
||||
SimpleTableWidgetItem.Row.Style,
|
||||
SimpleTableWidgetItem.Row.Delete,
|
||||
SimpleTableWidgetItem.Row.MoveUp,
|
||||
SimpleTableWidgetItem.Row.MoveDown,
|
||||
SimpleTableWidgetItem.Row.InsertAbove,
|
||||
SimpleTableWidgetItem.Row.InsertBelow,
|
||||
SimpleTableWidgetItem.Row.Duplicate,
|
||||
SimpleTableWidgetItem.Row.Sort
|
||||
),
|
||||
columnItems = listOf(
|
||||
SimpleTableWidgetItem.Column.ClearContents,
|
||||
SimpleTableWidgetItem.Column.Color,
|
||||
SimpleTableWidgetItem.Column.Style,
|
||||
SimpleTableWidgetItem.Column.Delete,
|
||||
SimpleTableWidgetItem.Column.InsertLeft,
|
||||
SimpleTableWidgetItem.Column.InsertRight,
|
||||
SimpleTableWidgetItem.Column.MoveLeft,
|
||||
SimpleTableWidgetItem.Column.MoveRight,
|
||||
SimpleTableWidgetItem.Column.Sort,
|
||||
SimpleTableWidgetItem.Column.Duplicate
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}.catch { e ->
|
||||
Timber.e(e, "Error while processing simple table ")
|
||||
}
|
||||
|
||||
override suspend fun onSimpleTableEvent(event: SimpleTableWidgetEvent) {
|
||||
events.emit(event)
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.editor.editor.table
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
|
||||
sealed interface SimpleTableWidgetEvent {
|
||||
data class onStart(val id: Id) : SimpleTableWidgetEvent
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.editor.editor.table
|
||||
|
||||
sealed class SimpleTableWidgetState {
|
||||
|
||||
object Idle : SimpleTableWidgetState()
|
||||
|
||||
data class UpdateItems(
|
||||
val cellItems: List<SimpleTableWidgetItem>,
|
||||
val columnItems: List<SimpleTableWidgetItem>,
|
||||
val rowItems: List<SimpleTableWidgetItem>
|
||||
) : SimpleTableWidgetState() {
|
||||
companion object {
|
||||
fun empty() = UpdateItems(
|
||||
cellItems = emptyList(),
|
||||
columnItems = emptyList(),
|
||||
rowItems = emptyList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun init(): SimpleTableWidgetState = Idle
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.editor.editor.table
|
||||
|
||||
sealed class SimpleTableWidgetViewState {
|
||||
object Idle : SimpleTableWidgetViewState()
|
||||
data class Active(val state: SimpleTableWidgetState) : SimpleTableWidgetViewState()
|
||||
}
|
|
@ -1994,7 +1994,8 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
selection = selection,
|
||||
rows = rows,
|
||||
columns = columns,
|
||||
blocks = blocks
|
||||
blocks = blocks,
|
||||
tableId = block.id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2008,11 +2009,13 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
block = block,
|
||||
selection = selection
|
||||
),
|
||||
background = block.parseThemeBackgroundColor()
|
||||
background = block.parseThemeBackgroundColor(),
|
||||
selectedCellsIds = selection.toList()
|
||||
)
|
||||
}
|
||||
|
||||
private fun tableCells(
|
||||
tableId: Id,
|
||||
blocks: Map<String, List<Block>>,
|
||||
rows: List<Block>,
|
||||
columns: List<BlockView.Table.Column>,
|
||||
|
@ -2051,6 +2054,7 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val cellIndex = columnIndex*rows.size + rowIndex
|
||||
cells.add(
|
||||
BlockView.Table.Cell(
|
||||
rowId = row.id,
|
||||
|
@ -2058,7 +2062,9 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
columnId = column.id,
|
||||
columnIndex = BlockView.Table.ColumnIndex(columnIndex),
|
||||
isHeader = isHeader,
|
||||
block = paragraph
|
||||
tableId = tableId,
|
||||
block = paragraph,
|
||||
cellIndex = cellIndex
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,378 @@
|
|||
package com.anytypeio.anytype.presentation.editor.selection
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableWidgetItem
|
||||
|
||||
fun updateTableCellsSelectionState(
|
||||
cellId: Id,
|
||||
rowIndex: BlockView.Table.RowIndex,
|
||||
columnIndex: BlockView.Table.ColumnIndex,
|
||||
selectionState: List<BlockView.Table.CellSelection>,
|
||||
cellIndex: Int
|
||||
): List<BlockView.Table.CellSelection> {
|
||||
|
||||
val latestSelection = BlockView.Table.CellSelection(
|
||||
cellId = cellId,
|
||||
rowIndex = rowIndex,
|
||||
columnIndex = columnIndex,
|
||||
left = true,
|
||||
top = true,
|
||||
right = true,
|
||||
bottom = true,
|
||||
cellIndex = cellIndex
|
||||
)
|
||||
|
||||
val latestSelectionIndex = selectionState.indexOfFirst { it.cellId == cellId }
|
||||
return if (latestSelectionIndex != -1) {
|
||||
//Latest selection is already in selection state - move on to deselecting a cell
|
||||
val newState = selectionState.toMutableList()
|
||||
newState.removeAt(latestSelectionIndex)
|
||||
newState.restoreBordersVisibility(deselectedSelection = latestSelection)
|
||||
newState
|
||||
} else {
|
||||
//Latest selection is not in selection state - move on to adding new selection to state
|
||||
selectionState.forEach { selection ->
|
||||
if (isLeftBorderMatch(cell1 = selection, cell2 = latestSelection)) {
|
||||
selection.left = false
|
||||
latestSelection.right = false
|
||||
}
|
||||
|
||||
if (isRightBorderMatch(cell1 = selection, cell2 = latestSelection)) {
|
||||
selection.right = false
|
||||
latestSelection.left = false
|
||||
}
|
||||
|
||||
if (isTopBorderMatch(cell1 = selection, cell2 = latestSelection)) {
|
||||
selection.top = false
|
||||
latestSelection.bottom = false
|
||||
}
|
||||
|
||||
if (isBottomBorderMatch(cell1 = selection, cell2 = latestSelection)) {
|
||||
selection.bottom = false
|
||||
latestSelection.top = false
|
||||
}
|
||||
}
|
||||
val newState = mutableListOf<BlockView.Table.CellSelection>().apply {
|
||||
addAll(selectionState)
|
||||
add(latestSelection)
|
||||
}
|
||||
newState
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In the case of deselecting the cell it is necessary
|
||||
* to restore the borders of the remaining selected cells
|
||||
*/
|
||||
fun List<BlockView.Table.CellSelection>.restoreBordersVisibility(deselectedSelection: BlockView.Table.CellSelection): List<BlockView.Table.CellSelection> =
|
||||
map { cellSelection ->
|
||||
if (isLeftBorderMatch(cell1 = cellSelection, cell2 = deselectedSelection)) {
|
||||
cellSelection.left = true
|
||||
}
|
||||
if (isRightBorderMatch(cell1 = cellSelection, cell2 = deselectedSelection)) {
|
||||
cellSelection.right = true
|
||||
}
|
||||
if (isTopBorderMatch(cell1 = cellSelection, cell2 = deselectedSelection)) {
|
||||
cellSelection.top = true
|
||||
}
|
||||
if (isBottomBorderMatch(cell1 = cellSelection, cell2 = deselectedSelection)) {
|
||||
cellSelection.bottom = true
|
||||
}
|
||||
cellSelection
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the left border of the first cell coincides with the right border of the second cell
|
||||
* |cell2|cell1|
|
||||
*/
|
||||
fun isLeftBorderMatch(
|
||||
cell1: BlockView.Table.CellSelection,
|
||||
cell2: BlockView.Table.CellSelection
|
||||
): Boolean {
|
||||
val isSameRow = cell1.rowIndex.value == cell2.rowIndex.value
|
||||
if (!isSameRow) return false
|
||||
return cell1.columnIndex.value == (cell2.columnIndex.value + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the right border of the first cell coincides with the left border of the second cell
|
||||
* |cell1|cell2|
|
||||
*/
|
||||
fun isRightBorderMatch(
|
||||
cell1: BlockView.Table.CellSelection,
|
||||
cell2: BlockView.Table.CellSelection
|
||||
): Boolean {
|
||||
val isSameRow = cell1.rowIndex.value == cell2.rowIndex.value
|
||||
if (!isSameRow) return false
|
||||
return cell2.columnIndex.value == (cell1.columnIndex.value + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the bottom border of the first cell coincides with the top border of the second cell
|
||||
* cell1
|
||||
* ------
|
||||
* cell2
|
||||
*/
|
||||
fun isBottomBorderMatch(
|
||||
cell1: BlockView.Table.CellSelection,
|
||||
cell2: BlockView.Table.CellSelection
|
||||
): Boolean {
|
||||
val isSameColumn = cell1.columnIndex.value == cell2.columnIndex.value
|
||||
if (!isSameColumn) return false
|
||||
return cell1.rowIndex.value + 1 == cell2.rowIndex.value
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the top border of the first cell coincides with the top bottom of the second cell
|
||||
* cell2
|
||||
* ------
|
||||
* cell1
|
||||
*/
|
||||
fun isTopBorderMatch(
|
||||
cell1: BlockView.Table.CellSelection,
|
||||
cell2: BlockView.Table.CellSelection
|
||||
): Boolean {
|
||||
val isSameColumn = cell1.columnIndex.value == cell2.columnIndex.value
|
||||
if (!isSameColumn) return false
|
||||
return cell1.rowIndex.value == cell2.rowIndex.value + 1
|
||||
}
|
||||
|
||||
fun List<BlockView>.toggleTableMode(
|
||||
cellsMode: BlockView.Mode,
|
||||
selectedCellsIds: List<Id>
|
||||
): List<BlockView> {
|
||||
return map { view ->
|
||||
when (view) {
|
||||
is BlockView.Text.Paragraph -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Checkbox -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Bulleted -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Numbered -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Highlight -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Callout -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Header.One -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Header.Two -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Header.Three -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Text.Toggle -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
is BlockView.Code -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Error.File -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Error.Video -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Error.Picture -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Error.Bookmark -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Upload.File -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Upload.Video -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Upload.Picture -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.MediaPlaceholder.File -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.MediaPlaceholder.Video -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.MediaPlaceholder.Bookmark -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.MediaPlaceholder.Picture -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Media.File -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Media.Video -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Media.Bookmark -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Media.Picture -> view.copy(
|
||||
mode = cellsMode,
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Title.Basic -> view.copy(
|
||||
mode = cellsMode
|
||||
)
|
||||
is BlockView.Title.Profile -> view.copy(
|
||||
mode = cellsMode
|
||||
)
|
||||
is BlockView.Title.Todo -> view.copy(
|
||||
mode = cellsMode
|
||||
)
|
||||
is BlockView.Title.Archive -> view.copy(
|
||||
mode = cellsMode
|
||||
)
|
||||
is BlockView.Description -> view.copy(
|
||||
mode = cellsMode
|
||||
)
|
||||
is BlockView.Relation.Placeholder -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Relation.Related -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.LinkToObject.Default.Text -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.LinkToObject.Default.Card.SmallIcon -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.LinkToObject.Default.Card.MediumIcon -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.LinkToObject.Default.Card.SmallIconCover -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.LinkToObject.Default.Card.MediumIconCover -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.LinkToObject.Archived -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.LinkToObject.Deleted -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.LinkToObject.Loading -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.DividerDots -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.DividerLine -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Latex -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.TableOfContents -> view.copy(
|
||||
isSelected = false
|
||||
)
|
||||
is BlockView.Table -> {
|
||||
view.copy(
|
||||
isSelected = false,
|
||||
cells = view.cells.updateCellsMode(mode = cellsMode),
|
||||
selectedCellsIds = selectedCellsIds
|
||||
)
|
||||
}
|
||||
is BlockView.FeaturedRelation -> view
|
||||
is BlockView.Unsupported -> view.copy(isSelected = false)
|
||||
is BlockView.Upload.Bookmark -> view.copy(isSelected = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun List<BlockView.Table.Cell>.updateCellsMode(
|
||||
mode: BlockView.Mode
|
||||
): List<BlockView.Table.Cell> = map { cell ->
|
||||
val block = cell.block
|
||||
if (block == null) {
|
||||
cell
|
||||
} else {
|
||||
cell.copy(
|
||||
block = block.copy(
|
||||
mode = mode,
|
||||
isSelected = false,
|
||||
isFocused = false,
|
||||
cursor = null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun List<BlockView>.updateTableBlockSelection(tableId: Id, selection: List<Id>): List<BlockView> =
|
||||
map {
|
||||
if (it.id == tableId && it is BlockView.Table) {
|
||||
it.copy(
|
||||
selectedCellsIds = selection
|
||||
)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
fun List<BlockView.Table.Cell>.getSimpleTableWidgetItems(): List<SimpleTableWidgetItem> {
|
||||
return listOf(
|
||||
SimpleTableWidgetItem.Cell.ClearContents
|
||||
// SimpleTableWidgetItem.Cell.Style,
|
||||
// SimpleTableWidgetItem.Cell.Color,
|
||||
// SimpleTableWidgetItem.Cell.ClearStyle
|
||||
)
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.anytypeio.anytype.presentation.editor.selection
|
||||
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class TableCellsSelectionState {
|
||||
|
||||
private var memory = listOf<BlockView.Table.CellSelection>()
|
||||
|
||||
fun set(cells: List<BlockView.Table.Cell>) {
|
||||
cells.forEach { cell ->
|
||||
val currentSelection = current()
|
||||
memory = updateTableCellsSelectionState(
|
||||
cellId = cell.getId(),
|
||||
rowIndex = cell.rowIndex,
|
||||
columnIndex = cell.columnIndex,
|
||||
selectionState = currentSelection,
|
||||
cellIndex = cell.cellIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
memory = emptyList()
|
||||
}
|
||||
|
||||
fun current(): List<BlockView.Table.CellSelection> = memory
|
||||
}
|
|
@ -27,6 +27,7 @@ import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
|||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.base.Result
|
||||
import com.anytypeio.anytype.domain.block.UpdateDivider
|
||||
import com.anytypeio.anytype.domain.block.interactor.ClearBlockContent
|
||||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.DuplicateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.MergeBlocks
|
||||
|
@ -101,8 +102,6 @@ import com.anytypeio.anytype.presentation.editor.editor.pattern.DefaultPatternMa
|
|||
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashItem
|
||||
import com.anytypeio.anytype.presentation.editor.editor.styling.StyleToolbarState
|
||||
import com.anytypeio.anytype.presentation.editor.editor.styling.StylingEvent
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.DefaultSimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
|
||||
import com.anytypeio.anytype.presentation.editor.render.parseThemeBackgroundColor
|
||||
import com.anytypeio.anytype.presentation.editor.selection.SelectionStateHolder
|
||||
|
@ -327,8 +326,6 @@ open class EditorViewModelTest {
|
|||
|
||||
private lateinit var editorTemplateDelegate: EditorTemplateDelegate
|
||||
|
||||
private lateinit var simpleTableDelegate: SimpleTableDelegate
|
||||
|
||||
@Mock
|
||||
lateinit var createNewObject: CreateNewObject
|
||||
|
||||
|
@ -344,6 +341,7 @@ open class EditorViewModelTest {
|
|||
private lateinit var setDocCoverImage: SetDocCoverImage
|
||||
private lateinit var setDocImageIcon: SetDocumentImageIcon
|
||||
private lateinit var objectToSet: ConvertObjectToSet
|
||||
private lateinit var clearBlockContent: ClearBlockContent
|
||||
|
||||
val root = MockDataFactory.randomUuid()
|
||||
|
||||
|
@ -377,7 +375,6 @@ open class EditorViewModelTest {
|
|||
getTemplates = getTemplates,
|
||||
applyTemplate = applyTemplate
|
||||
)
|
||||
simpleTableDelegate = DefaultSimpleTableDelegate()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -3942,6 +3939,7 @@ open class EditorViewModelTest {
|
|||
setDocCoverImage = SetDocCoverImage(repo)
|
||||
setDocImageIcon = SetDocumentImageIcon(repo)
|
||||
downloadUnsplashImage = DownloadUnsplashImage(unsplashRepo)
|
||||
clearBlockContent = ClearBlockContent(repo)
|
||||
|
||||
vm = EditorViewModel(
|
||||
openPage = openPage,
|
||||
|
@ -4000,7 +3998,8 @@ open class EditorViewModelTest {
|
|||
updateBlocksMark = updateBlocksMark,
|
||||
setObjectType = setObjectType,
|
||||
createTable = createTable,
|
||||
fillTableRow = fillTableRow
|
||||
fillTableRow = fillTableRow,
|
||||
clearBlockContent = clearBlockContent
|
||||
),
|
||||
analytics = analytics,
|
||||
dispatcher = Dispatcher.Default(),
|
||||
|
@ -4018,7 +4017,6 @@ open class EditorViewModelTest {
|
|||
setDocCoverImage = setDocCoverImage,
|
||||
setDocImageIcon = setDocImageIcon,
|
||||
templateDelegate = editorTemplateDelegate,
|
||||
simpleTableDelegate = simpleTableDelegate,
|
||||
createNewObject = createNewObject,
|
||||
objectToSet = objectToSet
|
||||
)
|
||||
|
|
|
@ -15,6 +15,7 @@ import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
|||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.base.Result
|
||||
import com.anytypeio.anytype.domain.block.UpdateDivider
|
||||
import com.anytypeio.anytype.domain.block.interactor.ClearBlockContent
|
||||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.DuplicateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.MergeBlocks
|
||||
|
@ -75,8 +76,6 @@ import com.anytypeio.anytype.presentation.editor.Editor
|
|||
import com.anytypeio.anytype.presentation.editor.EditorViewModel
|
||||
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
|
||||
import com.anytypeio.anytype.presentation.editor.editor.pattern.DefaultPatternMatcher
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.DefaultSimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.editor.table.SimpleTableDelegate
|
||||
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
|
||||
import com.anytypeio.anytype.presentation.editor.selection.SelectionStateHolder
|
||||
import com.anytypeio.anytype.presentation.editor.template.DefaultEditorTemplateDelegate
|
||||
|
@ -265,8 +264,6 @@ open class EditorPresentationTestSetup {
|
|||
@Mock
|
||||
lateinit var fillTableRow: FillTableRow
|
||||
|
||||
lateinit var simpleTableDelegate: SimpleTableDelegate
|
||||
|
||||
lateinit var editorTemplateDelegate: EditorTemplateDelegate
|
||||
|
||||
protected val builder: UrlBuilder get() = UrlBuilder(gateway)
|
||||
|
@ -276,6 +273,7 @@ open class EditorPresentationTestSetup {
|
|||
private lateinit var setDocCoverImage: SetDocCoverImage
|
||||
private lateinit var setDocImageIcon: SetDocumentImageIcon
|
||||
private lateinit var objectToSet: ConvertObjectToSet
|
||||
private lateinit var clearBlockContent: ClearBlockContent
|
||||
|
||||
open lateinit var orchestrator: Orchestrator
|
||||
|
||||
|
@ -293,11 +291,11 @@ open class EditorPresentationTestSetup {
|
|||
setDocCoverImage = SetDocCoverImage(repo)
|
||||
setDocImageIcon = SetDocumentImageIcon(repo)
|
||||
downloadUnsplashImage = DownloadUnsplashImage(unsplashRepo)
|
||||
simpleTableDelegate = DefaultSimpleTableDelegate()
|
||||
editorTemplateDelegate = DefaultEditorTemplateDelegate(
|
||||
getTemplates = getTemplates,
|
||||
applyTemplate = applyTemplate
|
||||
)
|
||||
clearBlockContent = ClearBlockContent(repo)
|
||||
|
||||
orchestrator = Orchestrator(
|
||||
createBlock = createBlock,
|
||||
|
@ -339,7 +337,8 @@ open class EditorPresentationTestSetup {
|
|||
updateBlocksMark = updateBlocksMark,
|
||||
setObjectType = setObjectType,
|
||||
createTable = createTable,
|
||||
fillTableRow = fillTableRow
|
||||
fillTableRow = fillTableRow,
|
||||
clearBlockContent = clearBlockContent
|
||||
)
|
||||
|
||||
return EditorViewModel(
|
||||
|
@ -376,7 +375,6 @@ open class EditorPresentationTestSetup {
|
|||
setDocCoverImage = setDocCoverImage,
|
||||
setDocImageIcon = setDocImageIcon,
|
||||
templateDelegate = editorTemplateDelegate,
|
||||
simpleTableDelegate = simpleTableDelegate,
|
||||
createNewObject = createNewObject,
|
||||
objectToSet = objectToSet
|
||||
)
|
||||
|
|
|
@ -0,0 +1,369 @@
|
|||
package com.anytypeio.anytype.presentation.editor.editor.ext
|
||||
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView.Table.CellSelection
|
||||
import com.anytypeio.anytype.presentation.editor.selection.TableCellsSelectionState
|
||||
import com.anytypeio.anytype.test_utils.MockDataFactory
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class TableCellsSelectionStateTest {
|
||||
|
||||
val tableId = MockDataFactory.randomUuid()
|
||||
|
||||
@Test
|
||||
fun `when click on cell expecting selected state with this cell`() {
|
||||
|
||||
//SETUP
|
||||
val cellsSelectionState = TableCellsSelectionState()
|
||||
|
||||
//TESTING
|
||||
//click on cell row1, column1
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row1",
|
||||
columnId = "column1",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
block = null,
|
||||
cellIndex = 22,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val actual = cellsSelectionState.current()
|
||||
|
||||
//EXPECTED
|
||||
val expected = listOf(
|
||||
CellSelection(
|
||||
cellId = "row1-column1",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
left = true,
|
||||
top = true,
|
||||
right = true,
|
||||
bottom = true,
|
||||
cellIndex = 22
|
||||
)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when clicking on the same sell expecting empty state`() {
|
||||
|
||||
//SETUP
|
||||
val cellsSelectionState = TableCellsSelectionState()
|
||||
|
||||
//TESTING
|
||||
//click on cell row1, column1
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row1",
|
||||
columnId = "column1",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
block = null,
|
||||
tableId = tableId,
|
||||
cellIndex = 11
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
//second click on cell row1, column1
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row1",
|
||||
columnId = "column1",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
block = null,
|
||||
cellIndex = 11,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val actual = cellsSelectionState.current()
|
||||
|
||||
//EXPECTED
|
||||
val expected = emptyList<CellSelection>()
|
||||
|
||||
//ASSERT
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when clicking on different cells expecting proper borders visibility`() {
|
||||
|
||||
//SETUP
|
||||
val cellsSelectionState = TableCellsSelectionState()
|
||||
|
||||
//TESTING
|
||||
//click on cell row1, column0
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row1",
|
||||
columnId = "column0",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = null,
|
||||
cellIndex = 1,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
//click on cell row1, column2
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row1",
|
||||
columnId = "column2",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
block = null,
|
||||
cellIndex = 7,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
//click on cell row2, column0
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row2",
|
||||
columnId = "column0",
|
||||
rowIndex = BlockView.Table.RowIndex(2),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = null,
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
//click on cell row0, column2
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row0",
|
||||
columnId = "column2",
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
block = null,
|
||||
cellIndex = 6,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
//click on cell row1, column1
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row1",
|
||||
columnId = "column1",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
block = null,
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val actual = cellsSelectionState.current()
|
||||
|
||||
//EXPECTED
|
||||
val expected = listOf(
|
||||
CellSelection(
|
||||
cellId = "row1-column0",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
left = true,
|
||||
top = true,
|
||||
right = false,
|
||||
bottom = false,
|
||||
cellIndex = 1
|
||||
),
|
||||
CellSelection(
|
||||
cellId = "row1-column2",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
left = false,
|
||||
top = false,
|
||||
right = true,
|
||||
bottom = true,
|
||||
cellIndex = 7
|
||||
),
|
||||
CellSelection(
|
||||
cellId = "row2-column0",
|
||||
rowIndex = BlockView.Table.RowIndex(2),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
left = true,
|
||||
top = false,
|
||||
right = true,
|
||||
bottom = true,
|
||||
cellIndex = 2
|
||||
),
|
||||
CellSelection(
|
||||
cellId = "row0-column2",
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
left = true,
|
||||
top = true,
|
||||
right = true,
|
||||
bottom = false,
|
||||
cellIndex = 6
|
||||
),
|
||||
CellSelection(
|
||||
cellId = "row1-column1",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
left = false,
|
||||
top = true,
|
||||
right = false,
|
||||
bottom = true,
|
||||
cellIndex = 4
|
||||
)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(5, actual.size, message = "Size of selected cells expected 5")
|
||||
assertEquals(expected, actual)
|
||||
|
||||
//TESTING
|
||||
//click on cell row1, column1
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row1",
|
||||
columnId = "column1",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
block = null,
|
||||
cellIndex = 4,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val actual2 = cellsSelectionState.current()
|
||||
|
||||
//EXPECTED
|
||||
val expected2 = listOf(
|
||||
CellSelection(
|
||||
cellId = "row1-column0",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
left = true,
|
||||
top = true,
|
||||
right = true,
|
||||
bottom = false,
|
||||
cellIndex = 1
|
||||
),
|
||||
CellSelection(
|
||||
cellId = "row1-column2",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
left = true,
|
||||
top = false,
|
||||
right = true,
|
||||
bottom = true,
|
||||
cellIndex = 7
|
||||
),
|
||||
CellSelection(
|
||||
cellId = "row2-column0",
|
||||
rowIndex = BlockView.Table.RowIndex(2),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
left = true,
|
||||
top = false,
|
||||
right = true,
|
||||
bottom = true,
|
||||
cellIndex = 2
|
||||
),
|
||||
CellSelection(
|
||||
cellId = "row0-column2",
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
left = true,
|
||||
top = true,
|
||||
right = true,
|
||||
bottom = false,
|
||||
cellIndex = 6
|
||||
)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(4, actual2.size, message = "Size of selected cells expected 4")
|
||||
assertEquals(expected2, actual2)
|
||||
|
||||
//TESTING
|
||||
//click on cell row0, column2
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row0",
|
||||
columnId = "column2",
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
block = null,
|
||||
cellIndex = 6,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
//click on cell row0, column2
|
||||
cellsSelectionState.set(
|
||||
cells = listOf(
|
||||
BlockView.Table.Cell(
|
||||
rowId = "row2",
|
||||
columnId = "column0",
|
||||
rowIndex = BlockView.Table.RowIndex(2),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = null,
|
||||
cellIndex = 2,
|
||||
tableId = tableId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val actual3 = cellsSelectionState.current()
|
||||
|
||||
//EXPECTED
|
||||
val expected3 = listOf(
|
||||
CellSelection(
|
||||
cellId = "row1-column0",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
left = true,
|
||||
top = true,
|
||||
right = true,
|
||||
bottom = true,
|
||||
cellIndex = 1
|
||||
),
|
||||
CellSelection(
|
||||
cellId = "row1-column2",
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
left = true,
|
||||
top = true,
|
||||
right = true,
|
||||
bottom = true,
|
||||
cellIndex = 7
|
||||
)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(2, actual3.size, message = "Size of selected cells expected 2")
|
||||
assertEquals(expected3, actual3)
|
||||
}
|
||||
}
|
|
@ -4,15 +4,18 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
|||
import com.anytypeio.anytype.core_models.StubHeader
|
||||
import com.anytypeio.anytype.core_models.StubLayoutColumns
|
||||
import com.anytypeio.anytype.core_models.StubLayoutRows
|
||||
import com.anytypeio.anytype.core_models.StubParagraph
|
||||
import com.anytypeio.anytype.core_models.StubSmartBlock
|
||||
import com.anytypeio.anytype.core_models.StubTable
|
||||
import com.anytypeio.anytype.core_models.StubTableCells
|
||||
import com.anytypeio.anytype.core_models.StubTableColumns
|
||||
import com.anytypeio.anytype.core_models.StubTableRows
|
||||
import com.anytypeio.anytype.core_models.StubTitle
|
||||
import com.anytypeio.anytype.core_models.ext.content
|
||||
import com.anytypeio.anytype.domain.table.FillTableRow
|
||||
import com.anytypeio.anytype.presentation.editor.editor.EditorPresentationTestSetup
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
|
@ -41,7 +44,10 @@ class EditorTableBlockTest : EditorPresentationTestSetup() {
|
|||
|
||||
val columns = StubTableColumns(size = 3)
|
||||
val rows = StubTableRows(size = 2)
|
||||
val cells = StubTableCells(columns = listOf(), rows = listOf())
|
||||
val cells = StubTableCells(
|
||||
columns = listOf(columns[0], columns[1], columns[2]),
|
||||
rows = listOf(rows[0], rows[1])
|
||||
)
|
||||
val columnLayout = StubLayoutColumns(children = columns.map { it.id })
|
||||
val rowLayout = StubLayoutRows(children = rows.map { it.id })
|
||||
val table = StubTable(children = listOf(columnLayout.id, rowLayout.id))
|
||||
|
@ -62,24 +68,33 @@ class EditorTableBlockTest : EditorPresentationTestSetup() {
|
|||
|
||||
val vm = buildViewModel()
|
||||
|
||||
val cell1Id = "${rows[0].id}-${columns[1].id}"
|
||||
val cell2Id = "${rows[1].id}-${columns[0].id}"
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onClickListener(
|
||||
ListenerType.TableEmptyCell(
|
||||
cellId = cell1Id,
|
||||
rowId = rows[0].id,
|
||||
tableId = table.id
|
||||
cell = BlockView.Table.Cell(
|
||||
rowId = rows[0].id,
|
||||
columnId = columns[1].id,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
block = null,
|
||||
cellIndex = 0,
|
||||
tableId = table.id
|
||||
)
|
||||
)
|
||||
)
|
||||
onClickListener(
|
||||
ListenerType.TableEmptyCell(
|
||||
cellId = cell2Id,
|
||||
rowId = rows[1].id,
|
||||
tableId = table.id
|
||||
cell = BlockView.Table.Cell(
|
||||
rowId = rows[1].id,
|
||||
columnId = columns[0].id,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = null,
|
||||
cellIndex = 1,
|
||||
tableId = table.id
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -98,7 +113,7 @@ class EditorTableBlockTest : EditorPresentationTestSetup() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `should amend second text cell click`() {
|
||||
fun `should not amend second text cell click`() {
|
||||
|
||||
val columns = StubTableColumns(size = 3)
|
||||
val rows = StubTableRows(size = 2)
|
||||
|
@ -121,22 +136,39 @@ class EditorTableBlockTest : EditorPresentationTestSetup() {
|
|||
stubOpenDocument(document)
|
||||
val vm = buildViewModel()
|
||||
|
||||
val cell1Id = "${rows[0].id}-${columns[1].id}"
|
||||
val cell2Id = "${rows[1].id}-${columns[0].id}"
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onClickListener(
|
||||
ListenerType.TableTextCell(
|
||||
cellId = cell1Id,
|
||||
tableId = table.id
|
||||
cell = BlockView.Table.Cell(
|
||||
rowId = rows[0].id,
|
||||
columnId = columns[1].id,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
block = BlockView.Text.Paragraph(
|
||||
id = cells[0].id,
|
||||
text = cells[0].content.asText().text
|
||||
),
|
||||
cellIndex = 0,
|
||||
tableId = table.id
|
||||
)
|
||||
)
|
||||
)
|
||||
onClickListener(
|
||||
ListenerType.TableTextCell(
|
||||
cellId = cell2Id,
|
||||
tableId = table.id
|
||||
cell = BlockView.Table.Cell(
|
||||
rowId = rows[1].id,
|
||||
columnId = columns[0].id,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = BlockView.Text.Paragraph(
|
||||
id = cells[1].id,
|
||||
text = cells[1].content.asText().text
|
||||
),
|
||||
cellIndex = 1,
|
||||
tableId = table.id
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -144,7 +176,6 @@ class EditorTableBlockTest : EditorPresentationTestSetup() {
|
|||
val selectedState = vm.currentSelection()
|
||||
runBlocking {
|
||||
assertEquals(1, selectedState.size)
|
||||
assertEquals(cell1Id, selectedState.first())
|
||||
verifyNoInteractions(fillTableRow)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,8 @@ class TableBlockRendererTest {
|
|||
class BlockViewRenderWrapper(
|
||||
private val blocks: Map<Id, List<Block>>,
|
||||
private val renderer: BlockViewRenderer,
|
||||
private val restrictions: List<ObjectRestriction> = emptyList()
|
||||
private val restrictions: List<ObjectRestriction> = emptyList(),
|
||||
private val selections: Set<Id> = emptySet()
|
||||
) : BlockViewRenderer by renderer {
|
||||
suspend fun render(
|
||||
root: Block,
|
||||
|
@ -59,7 +60,7 @@ class TableBlockRendererTest {
|
|||
details = details,
|
||||
relations = emptyList(),
|
||||
restrictions = restrictions,
|
||||
selection = emptySet(),
|
||||
selection = selections,
|
||||
objectTypes = listOf()
|
||||
)
|
||||
}
|
||||
|
@ -199,7 +200,9 @@ class TableBlockRendererTest {
|
|||
rowId = row.id,
|
||||
columnId = column.id,
|
||||
rowIndex = BlockView.Table.RowIndex(rowIndex),
|
||||
columnIndex = BlockView.Table.ColumnIndex(columnIndex)
|
||||
columnIndex = BlockView.Table.ColumnIndex(columnIndex),
|
||||
cellIndex = columnIndex*rows.size + rowIndex,
|
||||
tableId = table.id
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -243,7 +246,8 @@ class TableBlockRendererTest {
|
|||
cells = cells,
|
||||
columns = columnViews,
|
||||
rowCount = rowsSize,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
) + blocksDown.mapIndexed { idx, block ->
|
||||
BlockView.Text.Numbered(
|
||||
|
@ -351,7 +355,9 @@ class TableBlockRendererTest {
|
|||
columnId = column.id,
|
||||
rowIndex = BlockView.Table.RowIndex(rowIndex),
|
||||
columnIndex = BlockView.Table.ColumnIndex(columnIndex),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = columnIndex*rows.size + rowIndex,
|
||||
tableId = table.id
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -395,7 +401,8 @@ class TableBlockRendererTest {
|
|||
cells = cells,
|
||||
columns = columnViews,
|
||||
rowCount = rowsSize,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = emptyList()
|
||||
)
|
||||
) + blocksDown.mapIndexed { idx, block ->
|
||||
BlockView.Text.Numbered(
|
||||
|
@ -499,7 +506,8 @@ class TableBlockRendererTest {
|
|||
|
||||
wrapper = BlockViewRenderWrapper(
|
||||
blocks = map,
|
||||
renderer = renderer
|
||||
renderer = renderer,
|
||||
selections = setOf("$rowId2-$columnId1")
|
||||
)
|
||||
|
||||
val result = runBlocking {
|
||||
|
@ -519,7 +527,9 @@ class TableBlockRendererTest {
|
|||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 0,
|
||||
tableId = table.id
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId2,
|
||||
|
@ -529,14 +539,18 @@ class TableBlockRendererTest {
|
|||
text = row2Block1.content.asText().text
|
||||
),
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0)
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
cellIndex = 1,
|
||||
tableId = table.id
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId3,
|
||||
columnId = columnId1,
|
||||
rowIndex = BlockView.Table.RowIndex(2),
|
||||
columnIndex = BlockView.Table.ColumnIndex(0),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 2,
|
||||
tableId = table.id
|
||||
), //column1
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId1,
|
||||
|
@ -546,7 +560,9 @@ class TableBlockRendererTest {
|
|||
text = row1Block1.content.asText().text
|
||||
),
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 3,
|
||||
tableId = table.id
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId2,
|
||||
|
@ -556,35 +572,45 @@ class TableBlockRendererTest {
|
|||
text = row2Block2.content.asText().text
|
||||
),
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1)
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
cellIndex = 4,
|
||||
tableId = table.id
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId3,
|
||||
columnId = columnId2,
|
||||
rowIndex = BlockView.Table.RowIndex(2),
|
||||
columnIndex = BlockView.Table.ColumnIndex(1),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 5,
|
||||
tableId = table.id
|
||||
),//column2
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId1,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 6,
|
||||
tableId = table.id
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId2,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 7,
|
||||
tableId = table.id
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId3,
|
||||
columnId = columnId3,
|
||||
rowIndex = BlockView.Table.RowIndex(2),
|
||||
columnIndex = BlockView.Table.ColumnIndex(2),
|
||||
block = null
|
||||
block = null,
|
||||
cellIndex = 8,
|
||||
tableId = table.id
|
||||
),//column3
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId1,
|
||||
|
@ -594,7 +620,9 @@ class TableBlockRendererTest {
|
|||
text = row1Block2.content.asText().text
|
||||
),
|
||||
rowIndex = BlockView.Table.RowIndex(0),
|
||||
columnIndex = BlockView.Table.ColumnIndex(3)
|
||||
columnIndex = BlockView.Table.ColumnIndex(3),
|
||||
cellIndex = 9,
|
||||
tableId = table.id
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId2,
|
||||
|
@ -604,15 +632,19 @@ class TableBlockRendererTest {
|
|||
text = row2Block3.content.asText().text
|
||||
),
|
||||
rowIndex = BlockView.Table.RowIndex(1),
|
||||
columnIndex = BlockView.Table.ColumnIndex(3)
|
||||
columnIndex = BlockView.Table.ColumnIndex(3),
|
||||
cellIndex = 10,
|
||||
tableId = table.id
|
||||
),
|
||||
BlockView.Table.Cell(
|
||||
rowId = rowId3,
|
||||
columnId = columnId4,
|
||||
rowIndex = BlockView.Table.RowIndex(2),
|
||||
columnIndex = BlockView.Table.ColumnIndex(3),
|
||||
block = null
|
||||
),
|
||||
block = null,
|
||||
cellIndex = 11,
|
||||
tableId = table.id
|
||||
)
|
||||
)
|
||||
|
||||
val columnViews = mutableListOf<BlockView.Table.Column>()
|
||||
|
@ -653,7 +685,8 @@ class TableBlockRendererTest {
|
|||
cells = cells,
|
||||
columns = columnViews,
|
||||
rowCount = rowsSize,
|
||||
isSelected = false
|
||||
isSelected = false,
|
||||
selectedCellsIds = listOf("$rowId2-$columnId1")
|
||||
)
|
||||
) + blocksDown.mapIndexed { idx, block ->
|
||||
BlockView.Text.Numbered(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue