Skip to content

Instantly share code, notes, and snippets.

@loloof64
Last active February 3, 2021 18:17
Show Gist options
  • Save loloof64/048014437131a3b21acdf5b206d25908 to your computer and use it in GitHub Desktop.
Save loloof64/048014437131a3b21acdf5b206d25908 to your computer and use it in GitHub Desktop.
Jetpack compose alpha11 Drag and Drop in a strange checker board
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.gesture.DragObserver
import androidx.compose.ui.gesture.dragGestureFilter
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.platform.AmbientDensity
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import kotlin.math.floor
import android.graphics.Color as LegacyColor
class PiecesValues(initial: Array<Array<String?>>) {
private var internalValues = initial
fun getValueAt(row: Int, col: Int): String? {
return internalValues[row][col]
}
fun getColorAt(row: Int, col: Int): Color? {
return internalValues[row][col]?.let {
getColor(it)
}
}
fun setValueAt(row: Int, col: Int, value: String?) {
internalValues[row][col] = value
}
private fun getColor(colorString: String): Color {
return Color(LegacyColor.parseColor("#$colorString"))
}
}
@Composable
fun ItemsGrid(sizePx: Float, modifier: Modifier = Modifier) {
fun Float.getCoordFromAbsolute() : Int {
return floor((this - sizePx * 0.055f) / (sizePx * 0.11f)).toInt()
}
var dndStartX by remember { mutableStateOf(Float.NEGATIVE_INFINITY) }
var dndStartY by remember { mutableStateOf(Float.NEGATIVE_INFINITY) }
var dndDestX by remember { mutableStateOf(Float.NEGATIVE_INFINITY) }
var dndDestY by remember { mutableStateOf(Float.NEGATIVE_INFINITY) }
var values by remember {
mutableStateOf(
PiecesValues(
arrayOf(
arrayOf("DCBA23", "123456", null, "CB23DE", null, null, "45C38F", null),
arrayOf(null, null, null, "56E3DF", null, null, "45ED2C", null),
arrayOf(null, null, null, "CB23DE", null, null, null, null),
arrayOf("125687", null, null, null, null, null, null, null),
arrayOf(null, "89DC2F", null, null, null, null, null, null),
arrayOf(null, "123456", null, null, null, null, "DF52C9", null),
arrayOf(null, null, null, null, null, "ABCDEF", null, null),
arrayOf(null, "CAFEBABE", null, null, null, null, null, null),
)
)
)
}
val sizeDp = with(AmbientDensity.current) {
sizePx.toDp()
}
return Canvas(
modifier = modifier
.size(sizeDp)
.background(Color(LegacyColor.RED))
.dragGestureFilter(
dragObserver = object : DragObserver {
override fun onStart(downPosition: Offset) {
val selectedCol =
downPosition.x.getCoordFromAbsolute()
if (selectedCol < 0 || selectedCol > 7) return
val selectedRow =
downPosition.y.getCoordFromAbsolute()
if (selectedRow < 0 || selectedRow > 7) return
values.getColorAt(row = selectedRow, col = selectedCol) ?: return
dndStartX = downPosition.x
dndStartY = downPosition.y
dndDestX = downPosition.x
dndDestY = downPosition.y
}
override fun onDrag(dragDistance: Offset): Offset {
dndDestX += dragDistance.x
dndDestY += dragDistance.y
return dragDistance
}
override fun onStop(velocity: Offset) {
val startCol = dndStartX.getCoordFromAbsolute()
val startRow = dndStartY.getCoordFromAbsolute()
val endCol = dndDestX.getCoordFromAbsolute()
val endRow = dndDestY.getCoordFromAbsolute()
if (endCol < 0 || endCol > 7 || endRow < 0 || endRow > 7) {
onCancel()
return
}
val startCellValue = values.getValueAt(col = startCol, row = startRow)
values.setValueAt(col = startCol, row = startRow, value = null)
values.setValueAt(col = endCol, row = endRow, value = startCellValue)
onCancel()
}
override fun onCancel() {
dndStartX = Float.NEGATIVE_INFINITY
dndStartY = Float.NEGATIVE_INFINITY
dndDestX = Float.NEGATIVE_INFINITY
dndDestY = Float.NEGATIVE_INFINITY
}
},
startDragImmediately = true,
)
) {
val startCol = dndStartX.getCoordFromAbsolute()
val startRow = dndStartY.getCoordFromAbsolute()
val selectedCol = dndDestX.getCoordFromAbsolute()
val selectedRow = dndDestY.getCoordFromAbsolute()
(0 until 8).forEach { row ->
(0 until 8).forEach { col ->
val isDndStartCell = startCol == col && startRow == row
val isDndDestCell = selectedCol == col && selectedRow == row
val isDndCrossCell = selectedCol == col || selectedRow == row
val whiteCell = (row + col) % 2 == 0
var color = if (whiteCell) Color(LegacyColor.WHITE) else Color(LegacyColor.BLACK)
if (isDndStartCell) color = Color(LegacyColor.RED)
if (isDndCrossCell) color = Color(LegacyColor.MAGENTA)
if (isDndDestCell) color = Color(LegacyColor.GREEN)
drawCell(size = sizeDp / 9, row = row, col = col, color = color)
values.getColorAt(row, col)?.let {
val isTheDraggedPiece = startCol == col && startRow == row
val x = if (isTheDraggedPiece) dndDestX else sizePx * 0.11f * (1.0f + col)
val y = if (isTheDraggedPiece) dndDestY else sizePx * 0.11f * (1.0f + row)
drawItem(x, y, sizeDp / 9, it)
}
}
}
}
}
fun DrawScope.drawCell(size: Dp, row: Int, col: Int, color: Color) {
val x = size.toPx() * (0.5f + col)
val y = size.toPx() * (0.5f + row)
drawRect(color = color, topLeft = Offset(x, y), size = Size(size.toPx(), size.toPx()))
}
fun DrawScope.drawItem(x: Float, y: Float, size: Dp, color: Color) {
drawCircle(color = color, radius = size.toPx() * 0.5f, center = Offset(x, y))
}
@Preview
@Composable
fun ItemsGridPreview() {
val sizePx = with(AmbientDensity.current) { 300.dp.toPx() }
return ItemsGrid(sizePx)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment