package com.parkplants.ui.components import android.os.Build import android.text.Editable import android.text.InputType import android.text.TextWatcher import android.text.method.PasswordTransformationMethod import android.widget.EditText import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView private val Green = Color(0xFF22C55E) private val BorderDefault = Color(0xFF334155) private val PlaceholderColor = Color(0xFF64748B) private val LabelColor = Color(0xFF94A3B8) // Жёстко прописанные цвета в ARGB — никакая Compose-тема не затрагивает нативный EditText private val TEXT_COLOR_ARGB = android.graphics.Color.parseColor("#F1F5F9") private val HINT_COLOR_ARGB = android.graphics.Color.parseColor("#64748B") @Composable fun AppTextField( value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier, label: String = "", placeholder: String = "", enabled: Boolean = true, singleLine: Boolean = true, password: Boolean = false, passwordVisible: Boolean = false, trailingIcon: @Composable (() -> Unit)? = null, ) { var focused by remember { mutableStateOf(false) } val borderColor = if (focused) Green else BorderDefault Column(modifier = modifier) { if (label.isNotEmpty()) { Text( text = label, style = TextStyle( color = LabelColor, fontSize = 13.sp, fontWeight = FontWeight.Medium, ), modifier = Modifier.padding(bottom = 5.dp), ) } Row( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(10.dp)) .background(Color(0xFF273548)) .border(1.5.dp, borderColor, RoundedCornerShape(10.dp)) .padding(start = 14.dp, end = if (trailingIcon != null) 4.dp else 14.dp), verticalAlignment = Alignment.CenterVertically, ) { AndroidView( modifier = Modifier.weight(1f), factory = { context -> EditText(context).apply { // Прямые нативные API — не зависят от Compose-темы вообще setTextColor(TEXT_COLOR_ARGB) setHintTextColor(HINT_COLOR_ARGB) setBackgroundColor(android.graphics.Color.TRANSPARENT) textSize = 16f hint = placeholder isSingleLine = singleLine maxLines = if (singleLine) 1 else Int.MAX_VALUE isEnabled = enabled // padding в пикселях: 13dp * density val px13 = (13 * context.resources.displayMetrics.density).toInt() setPadding(0, px13, 0, px13) // Запрещаем Force Dark конкретно для этого View (API 29+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { isForceDarkAllowed = false } // Пароль if (password && !passwordVisible) { transformationMethod = PasswordTransformationMethod.getInstance() inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD } setOnFocusChangeListener { _, hasFocus -> focused = hasFocus } addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { val new = s?.toString() ?: "" if (new != value) onValueChange(new) } }) } }, update = { et -> // Обновляем трансформацию пароля при нажатии "показать" if (password) { val isPwdMode = et.transformationMethod is PasswordTransformationMethod if (passwordVisible && isPwdMode) { et.transformationMethod = null et.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD et.setSelection(et.text?.length ?: 0) } else if (!passwordVisible && !isPwdMode) { et.transformationMethod = PasswordTransformationMethod.getInstance() et.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD et.setSelection(et.text?.length ?: 0) } } // Обновляем текст только если он изменился снаружи if (et.text?.toString() != value) { et.setText(value) et.setSelection(value.length) } }, ) if (trailingIcon != null) { trailingIcon() } } } } /** Поле ввода пароля с кнопкой показать/скрыть */ @Composable fun AppPasswordField( value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier, label: String = "", placeholder: String = "", enabled: Boolean = true, ) { var visible by remember { mutableStateOf(false) } AppTextField( value = value, onValueChange = onValueChange, modifier = modifier, label = label, placeholder = placeholder, enabled = enabled, singleLine = true, password = true, passwordVisible = visible, trailingIcon = { IconButton(onClick = { visible = !visible }, modifier = Modifier.size(40.dp)) { Icon( imageVector = if (visible) Icons.Default.VisibilityOff else Icons.Default.Visibility, contentDescription = if (visible) "Скрыть пароль" else "Показать пароль", tint = PlaceholderColor, modifier = Modifier.size(20.dp), ) } }, ) }