⎇ 6f37139d565f0b409d34afbcb8c6f9f2bacdb3bc
keyboard/src/main/java/com/rizoma/trazo/MainActivity.kt
Ñawpa willay
ch'uya
fix: agregar imports faltantes (offset, getValue) y corregir CenterVertical/updateHaptics
1package com.rizoma.trazo
2
3import android.content.Context
4import android.content.Intent
5import android.os.Bundle
6import android.provider.Settings
7import android.view.inputmethod.InputMethodManager
8import androidx.activity.ComponentActivity
9import androidx.activity.compose.setContent
10import androidx.compose.foundation.background
11import androidx.compose.foundation.border
12import androidx.compose.foundation.clickable
13import androidx.compose.foundation.layout.Arrangement
14import androidx.compose.foundation.layout.Box
15import androidx.compose.foundation.layout.Column
16import androidx.compose.foundation.layout.Row
17import androidx.compose.foundation.layout.Spacer
18import androidx.compose.foundation.layout.fillMaxSize
19import androidx.compose.foundation.layout.fillMaxWidth
20import androidx.compose.foundation.layout.height
21import androidx.compose.foundation.layout.padding
22import androidx.compose.foundation.layout.width
23import androidx.compose.foundation.rememberScrollState
24import androidx.compose.foundation.shape.RoundedCornerShape
25import androidx.compose.foundation.verticalScroll
26import androidx.compose.material3.Text
27import androidx.compose.runtime.Composable
28import androidx.compose.ui.Alignment
29import androidx.compose.ui.Modifier
30import androidx.compose.ui.draw.clip
31import androidx.compose.ui.graphics.Color
32import androidx.compose.ui.text.font.FontWeight
33import androidx.compose.ui.unit.dp
34import androidx.compose.ui.unit.sp
35import androidx.core.view.WindowCompat
36import androidx.lifecycle.lifecycleScope
37import com.rizoma.trazo.data.HapticLevel
38import com.rizoma.trazo.data.TrazoSettings
39import com.rizoma.trazo.ui.theme.NeonCian
40import com.rizoma.trazo.ui.theme.NeonRosa
41import com.rizoma.trazo.ui.theme.NeonVerde
42import com.rizoma.trazo.ui.theme.Tecla
43import com.rizoma.trazo.ui.theme.Tenue
44import com.rizoma.trazo.ui.theme.TrazoTheme
45import com.rizoma.trazo.ui.theme.Vacio
46
47/** Pantalla para activar Trazo, elegirlo como teclado y ajustar sus preferencias. */
48class MainActivity : ComponentActivity() {
49
50 private lateinit var settings: TrazoSettings
51
52 override fun onCreate(savedInstanceState: Bundle?) {
53 super.onCreate(savedInstanceState)
54 settings = TrazoSettings(this, lifecycleScope)
55 WindowCompat.setDecorFitsSystemWindows(window, false)
56 setContent {
57 TrazoTheme {
58 Setup(
59 settings = settings,
60 onActivar = { startActivity(Intent(Settings.ACTION_INPUT_METHOD_SETTINGS)) },
61 onElegir = {
62 (getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
63 .showInputMethodPicker()
64 },
65 )
66 }
67 }
68 }
69}
70
71@Composable
72private fun Setup(settings: TrazoSettings, onActivar: () -> Unit, onElegir: () -> Unit) {
73 Column(
74 Modifier
75 .fillMaxSize()
76 .background(Vacio)
77 .verticalScroll(rememberScrollState())
78 .padding(horizontal = 32.dp, vertical = 56.dp),
79 ) {
80 Text("Trazo", color = NeonVerde, fontSize = 44.sp, fontWeight = FontWeight.Light)
81 Spacer(Modifier.height(8.dp))
82 Text("teclado de trazos — un toque, ocho gestos.", color = Tenue, fontSize = 15.sp)
83 Spacer(Modifier.height(36.dp))
84
85 Paso("1", "activa Trazo en ajustes del sistema", NeonCian, onActivar)
86 Spacer(Modifier.height(16.dp))
87 Paso("2", "elígelo como teclado actual", NeonRosa, onElegir)
88
89 Spacer(Modifier.height(40.dp))
90 Seccion("ajustes")
91 Spacer(Modifier.height(12.dp))
92
93 Toggle("vibración al teclear", settings.haptics, NeonCian) { settings.updateHaptics(it) }
94 if (settings.haptics) {
95 Spacer(Modifier.height(10.dp))
96 NivelHaptico(settings.hapticLevel) { settings.updateHapticLevel(it) }
97 }
98
99 Spacer(Modifier.height(10.dp))
100 Toggle("doble espacio → punto", settings.doubleSpacePeriod, NeonVerde) {
101 settings.updateDoubleSpacePeriod(it)
102 }
103
104 Spacer(Modifier.height(24.dp))
105 Seccion("idiomas de predicción")
106 Spacer(Modifier.height(12.dp))
107 Toggle("español", settings.spanish, NeonRosa) { settings.updateSpanish(it) }
108 Spacer(Modifier.height(10.dp))
109 Toggle("inglés", settings.english, NeonCian) { settings.updateEnglish(it) }
110 }
111}
112
113@Composable
114private fun Seccion(titulo: String) {
115 Text(titulo, color = Tenue, fontSize = 13.sp, fontWeight = FontWeight.Medium)
116}
117
118@Composable
119private fun Paso(num: String, label: String, accent: Color, onClick: () -> Unit) {
120 Column(
121 Modifier
122 .fillMaxWidth()
123 .clip(RoundedCornerShape(18.dp))
124 .background(Tecla)
125 .border(1.dp, accent.copy(alpha = 0.4f), RoundedCornerShape(18.dp))
126 .clickable(onClick = onClick)
127 .padding(20.dp),
128 ) {
129 Text(num, color = accent, fontSize = 13.sp, fontWeight = FontWeight.Bold)
130 Spacer(Modifier.height(6.dp))
131 Text(label, color = Color.White, fontSize = 17.sp)
132 }
133}
134
135@Composable
136private fun Toggle(label: String, value: Boolean, accent: Color, onChange: (Boolean) -> Unit) {
137 Row(
138 Modifier
139 .fillMaxWidth()
140 .clip(RoundedCornerShape(14.dp))
141 .background(Tecla)
142 .clickable { onChange(!value) }
143 .padding(horizontal = 18.dp, vertical = 16.dp),
144 verticalAlignment = Alignment.CenterVertically,
145 ) {
146 Text(label, color = Color.White, fontSize = 16.sp, modifier = Modifier.weight(1f))
147 Pill(value, accent)
148 }
149}
150
151/** Indicador tipo interruptor: relleno y a la derecha cuando está activo. */
152@Composable
153private fun Pill(on: Boolean, accent: Color) {
154 Box(
155 Modifier
156 .width(46.dp)
157 .height(26.dp)
158 .clip(RoundedCornerShape(13.dp))
159 .background(if (on) accent.copy(alpha = 0.28f) else Color(0xFF1B1B26))
160 .border(1.dp, if (on) accent else Tenue, RoundedCornerShape(13.dp)),
161 contentAlignment = if (on) Alignment.CenterEnd else Alignment.CenterStart,
162 ) {
163 Box(
164 Modifier
165 .padding(3.dp)
166 .width(20.dp)
167 .height(20.dp)
168 .clip(RoundedCornerShape(10.dp))
169 .background(if (on) accent else Tenue),
170 )
171 }
172}
173
174@Composable
175private fun NivelHaptico(level: HapticLevel, onSelect: (HapticLevel) -> Unit) {
176 Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
177 HapticLevel.entries.forEach { opt ->
178 val selected = opt == level
179 Box(
180 Modifier
181 .weight(1f)
182 .clip(RoundedCornerShape(12.dp))
183 .background(if (selected) NeonCian.copy(alpha = 0.18f) else Tecla)
184 .border(
185 1.dp,
186 if (selected) NeonCian else Tenue.copy(alpha = 0.4f),
187 RoundedCornerShape(12.dp),
188 )
189 .clickable { onSelect(opt) }
190 .padding(vertical = 12.dp),
191 contentAlignment = Alignment.Center,
192 ) {
193 Text(
194 text = opt.name.lowercase(),
195 color = if (selected) NeonCian else Tenue,
196 fontSize = 14.sp,
197 )
198 }
199 }
200 }
201}