Профиль, редактирование без аватара

This commit is contained in:
Халимов Рустам
2026-04-16 15:41:22 +03:00
parent 8409c51842
commit cea3f4d669
45 changed files with 1063 additions and 178 deletions

View File

@@ -12,8 +12,10 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.CalendarToday
import androidx.compose.material.icons.filled.CameraAlt
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@@ -30,6 +32,10 @@ import core.presentation.components.AppAvatar
import core.presentation.theme.SoftSquareShape
import ru.knot.messager.R
import android.app.DatePickerDialog
import java.text.SimpleDateFormat
import java.util.*
import android.app.Activity
import android.content.Intent
import com.yalantis.ucrop.UCrop
@@ -43,14 +49,62 @@ fun EditProfileScreen(
currentDisplayName: String?,
currentUsername: String,
currentBio: String?,
currentBirthday: String?,
currentAvatarUrl: String?,
onSave: (displayName: String, bio: String, avatarUri: Uri?) -> Unit,
isSaving: Boolean = false,
error: String? = null,
onSave: (displayName: String, bio: String, birthday: String?, avatarUri: Uri?) -> Unit,
onBack: () -> Unit
) {
val context = LocalContext.current
var displayName by remember { mutableStateOf(currentDisplayName ?: "") }
var bio by remember { mutableStateOf(currentBio ?: "") }
var displayName by remember(currentDisplayName) { mutableStateOf(currentDisplayName ?: "") }
var bio by remember(currentBio) { mutableStateOf(currentBio ?: "") }
var birthday by remember(currentBirthday) { mutableStateOf(currentBirthday ?: "") }
var selectedImageUri by remember { mutableStateOf<Uri?>(null) }
var showDatePicker by remember { mutableStateOf(false) }
// Парсим текущую дату для инициализации DatePicker и отображения
val calendar = Calendar.getInstance()
var formattedBirthday by remember { mutableStateOf("") }
if (birthday.isNotEmpty()) {
try {
// Пробуем распарсить ISO8601 формат (yyyy-MM-dd или yyyy-MM-ddTHH:mm:ss)
val format = when {
birthday.contains("T") -> SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault())
birthday.length == 10 -> SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
else -> SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
}
format.parse(birthday)?.let {
calendar.time = it
// Форматируем для отображения: ДД.ММ.ГГГГ
formattedBirthday = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).format(it)
}
} catch (e: Exception) {
formattedBirthday = birthday
}
}
// DatePickerDialog
if (showDatePicker) {
DatePickerDialog(
context,
{ _, year, month, dayOfMonth ->
val selectedCalendar = Calendar.getInstance()
selectedCalendar.set(year, month, dayOfMonth)
// Используем ISO8601 формат для отправки на сервер
val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
birthday = format.format(selectedCalendar.time)
},
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
).apply {
datePicker.maxDate = System.currentTimeMillis()
show()
}
showDatePicker = false
}
// Лаунчер для результата кропа
val cropLauncher = rememberLauncherForActivityResult(
@@ -78,17 +132,28 @@ fun EditProfileScreen(
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.edit_profile)) },
title = { Text(stringResource(R.string.edit_profile), fontWeight = FontWeight.Bold) },
navigationIcon = {
IconButton(onClick = onBack) {
Icon(Icons.Default.ArrowBack, contentDescription = stringResource(R.string.back))
}
},
actions = {
IconButton(onClick = { onSave(displayName, bio, selectedImageUri) }) {
Icon(Icons.Default.Check, contentDescription = stringResource(R.string.save), tint = MaterialTheme.colorScheme.primary)
TextButton(
onClick = { onSave(displayName, bio, birthday, selectedImageUri) },
enabled = !isSaving
) {
Text(
if (isSaving) stringResource(R.string.saving) else stringResource(R.string.save),
fontWeight = FontWeight.Bold,
color = if (isSaving) Color.Gray else MaterialTheme.colorScheme.primary
)
}
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
titleContentColor = Color.White
)
)
}
) { paddingValues ->
@@ -132,13 +197,14 @@ fun EditProfileScreen(
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.3f)),
.background(Color.Black.copy(alpha = 0.4f)),
contentAlignment = Alignment.Center
) {
Icon(
Icons.Default.CameraAlt,
contentDescription = stringResource(R.string.change_photo),
tint = Color.White
tint = Color.White.copy(alpha = 0.8f),
modifier = Modifier.size(28.dp)
)
}
}
@@ -194,14 +260,65 @@ fun EditProfileScreen(
maxLines = 5
)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = formattedBirthday,
onValueChange = { },
label = { Text("Дата рождения") },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
shape = SoftSquareShape,
placeholder = { Text("ДД.ММ.ГГГГ") },
trailingIcon = {
Row {
if (birthday.isNotEmpty()) {
IconButton(onClick = { birthday = "" }) {
Icon(
Icons.Default.Clear,
contentDescription = "Очистить",
tint = Color.Gray
)
}
}
IconButton(onClick = { showDatePicker = true }) {
Icon(
Icons.Default.CalendarToday,
contentDescription = "Выбрать дату",
tint = MaterialTheme.colorScheme.primary
)
}
}
}
)
if (error != null) {
Text(
text = error,
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(top = 8.dp)
)
}
Spacer(modifier = Modifier.height(32.dp))
Button(
onClick = { onSave(displayName, bio, selectedImageUri) },
onClick = { onSave(displayName, bio, birthday, selectedImageUri) },
modifier = Modifier.fillMaxWidth(),
shape = SoftSquareShape
shape = SoftSquareShape,
enabled = !isSaving
) {
Text(stringResource(R.string.save))
if (isSaving) {
CircularProgressIndicator(
modifier = Modifier.size(24.dp),
color = Color.White,
strokeWidth = 2.dp
)
Spacer(modifier = Modifier.width(8.dp))
Text(stringResource(R.string.saving))
} else {
Text(stringResource(R.string.save))
}
}
}
}