tawasuyu

sergio/humanoid

HTML 38Markdown 1TOML 10 Sutichaykuna

⎇ 5227fbf1abfb2a437968ebc63692560c3a929230 keyboard/src/main/java/com/rizoma/trazo/ui/KeyCell.kt 110 siq'ikuna · 4.0 KB Ñawpa willay ch'uya

Trazo: arreglar cursor al reposicionar + mayúsculas en R↑ y columna reordenada 5227fbf1a · Sergio ·

1package com.rizoma.trazo.ui
2
3import androidx.compose.foundation.background
4import androidx.compose.foundation.border
5import androidx.compose.foundation.gestures.awaitEachGesture
6import androidx.compose.foundation.gestures.awaitFirstDown
7import androidx.compose.foundation.layout.Box
8import androidx.compose.foundation.layout.fillMaxSize
9import androidx.compose.foundation.layout.padding
10import androidx.compose.foundation.shape.RoundedCornerShape
11import androidx.compose.material3.Text
12import androidx.compose.runtime.Composable
13import androidx.compose.ui.Alignment
14import androidx.compose.ui.Modifier
15import androidx.compose.ui.draw.clip
16import androidx.compose.ui.graphics.Color
17import androidx.compose.ui.input.pointer.pointerInput
18import androidx.compose.ui.platform.LocalDensity
19import androidx.compose.ui.text.font.FontWeight
20import androidx.compose.ui.unit.dp
21import androidx.compose.ui.unit.sp
22import com.rizoma.trazo.model.Dir
23import com.rizoma.trazo.model.KeyDef
24import com.rizoma.trazo.model.directionOf
25import com.rizoma.trazo.ui.theme.NeonVerde
26import com.rizoma.trazo.ui.theme.Tecla
27import com.rizoma.trazo.ui.theme.Tenue
28
29private val hintAlignments = mapOf(
30    Dir.N to Alignment.TopCenter,
31    Dir.NE to Alignment.TopEnd,
32    Dir.E to Alignment.CenterEnd,
33    Dir.SE to Alignment.BottomEnd,
34    Dir.S to Alignment.BottomCenter,
35    Dir.SW to Alignment.BottomStart,
36    Dir.W to Alignment.CenterStart,
37    Dir.NW to Alignment.TopStart,
38)
39
40@Composable
41fun KeyCell(
42    key: KeyDef,
43    shifted: Boolean,
44    onChar: (Char) -> Unit,
45    onShift: () -> Unit = {},
46    shiftAccent: Color = Tenue,
47    modifier: Modifier = Modifier,
48) {
49    val tapRadiusPx = with(LocalDensity.current) { 22.dp.toPx() }
50
51    Box(
52        modifier
53            .padding(3.dp)
54            .clip(RoundedCornerShape(14.dp))
55            .background(Tecla)
56            .border(1.dp, NeonVerde.copy(alpha = 0.10f), RoundedCornerShape(14.dp))
57            .pointerInput(key, shifted) {
58                awaitEachGesture {
59                    val down = awaitFirstDown()
60                    var current = down.position
61                    while (true) {
62                        val event = awaitPointerEvent()
63                        val change = event.changes.firstOrNull { it.id == down.id } ?: event.changes.first()
64                        current = change.position
65                        change.consume()
66                        if (!change.pressed) break
67                    }
68                    val dx = current.x - down.position.x
69                    val dy = current.y - down.position.y
70                    val dir = directionOf(dx, dy, tapRadiusPx)
71                    if (key.shiftDir != null && dir == key.shiftDir) onShift()
72                    else key.charFor(dir)?.let { raw -> onChar(raw) }
73                }
74            },
75    ) {
76        // Pistas de swipe (tenues) en los bordes.
77        key.swipes.forEach { (dir, ch) ->
78            val align = hintAlignments[dir] ?: return@forEach
79            Text(
80                text = glyph(ch, shifted),
81                color = Tenue,
82                fontSize = 11.sp,
83                modifier = Modifier.align(align).padding(horizontal = 6.dp, vertical = 3.dp),
84            )
85        }
86        // Pista de mayúsculas (R↑): coloreada según el estado del shift.
87        key.shiftDir?.let { d ->
88            hintAlignments[d]?.let { align ->
89                Text(
90                    text = "⇧",
91                    color = shiftAccent,
92                    fontSize = 13.sp,
93                    fontWeight = FontWeight.Bold,
94                    modifier = Modifier.align(align).padding(horizontal = 6.dp, vertical = 3.dp),
95                )
96            }
97        }
98        // Carácter central.
99        Text(
100            text = glyph(key.center, shifted),
101            color = androidx.compose.ui.graphics.Color.White,
102            fontSize = 22.sp,
103            fontWeight = FontWeight.Medium,
104            modifier = Modifier.align(Alignment.Center),
105        )
106    }
107}
108
109private fun glyph(c: Char, shifted: Boolean): String =
110    if (shifted) c.uppercaseChar().toString() else c.toString()