Files
forkmessager/client-mobile/profiles/presentation/EditProfileScreen.kt
Халимов Рустам 1fb1be47dd Приложение
2026-04-14 01:15:54 +03:00

209 lines
7.8 KiB
Kotlin

package profiles.presentation
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
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.CameraAlt
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.*
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.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.platform.LocalContext
import coil.compose.AsyncImage
import core.presentation.components.AppAvatar
import core.presentation.theme.SoftSquareShape
import ru.knot.messager.R
import android.app.Activity
import android.content.Intent
import com.yalantis.ucrop.UCrop
import core.utils.ImageCropper
import java.io.File
import java.util.UUID
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditProfileScreen(
currentDisplayName: String?,
currentUsername: String,
currentBio: String?,
currentAvatarUrl: String?,
onSave: (displayName: String, bio: String, avatarUri: Uri?) -> Unit,
onBack: () -> Unit
) {
val context = LocalContext.current
var displayName by remember { mutableStateOf(currentDisplayName ?: "") }
var bio by remember { mutableStateOf(currentBio ?: "") }
var selectedImageUri by remember { mutableStateOf<Uri?>(null) }
// Лаунчер для результата кропа
val cropLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
onResult = { result ->
if (result.resultCode == Activity.RESULT_OK && result.data != null) {
selectedImageUri = UCrop.getOutput(result.data!!)
}
}
)
// Лаунчер для выбора фото из галереи
val photoPickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia(),
onResult = { uri ->
if (uri != null) {
// После выбора фото запускаем UCrop
val destinationUri = Uri.fromFile(File(context.cacheDir, "${UUID.randomUUID()}.jpg"))
val cropIntent = ImageCropper.getCropIntent(context, uri, destinationUri).getIntent(context)
cropLauncher.launch(cropIntent)
}
}
)
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.edit_profile)) },
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)
}
}
)
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.verticalScroll(rememberScrollState())
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// Смена фото
Box(
modifier = Modifier
.size(120.dp)
.clip(SoftSquareShape)
.background(MaterialTheme.colorScheme.surfaceVariant)
.clickable {
photoPickerLauncher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)
},
contentAlignment = Alignment.Center
) {
if (selectedImageUri != null) {
AsyncImage(
model = selectedImageUri,
contentDescription = null,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop
)
} else {
AppAvatar(
url = currentAvatarUrl,
name = currentUsername,
size = 120.dp
)
}
// Overlay
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.3f)),
contentAlignment = Alignment.Center
) {
Icon(
Icons.Default.CameraAlt,
contentDescription = stringResource(R.string.change_photo),
tint = Color.White
)
}
}
TextButton(
onClick = {
photoPickerLauncher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)
},
modifier = Modifier.padding(top = 8.dp)
) {
Text(stringResource(R.string.change_photo))
}
Spacer(modifier = Modifier.height(32.dp))
// Поля ввода
OutlinedTextField(
value = displayName,
onValueChange = { displayName = it },
label = { Text(stringResource(R.string.display_name)) },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
shape = SoftSquareShape
)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = "@$currentUsername",
onValueChange = {},
label = { Text(stringResource(R.string.username_label)) },
modifier = Modifier.fillMaxWidth(),
enabled = false, // Обычно username меняется отдельно или вообще не меняется
shape = SoftSquareShape,
colors = OutlinedTextFieldDefaults.colors(
disabledBorderColor = MaterialTheme.colorScheme.outlineVariant,
disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant
)
)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = bio,
onValueChange = { bio = it },
label = { Text(stringResource(R.string.bio)) },
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 100.dp),
shape = SoftSquareShape,
maxLines = 5
)
Spacer(modifier = Modifier.height(32.dp))
Button(
onClick = { onSave(displayName, bio, selectedImageUri) },
modifier = Modifier.fillMaxWidth(),
shape = SoftSquareShape
) {
Text(stringResource(R.string.save))
}
}
}
}