Приложение
This commit is contained in:
208
client-mobile/profiles/presentation/EditProfileScreen.kt
Normal file
208
client-mobile/profiles/presentation/EditProfileScreen.kt
Normal file
@@ -0,0 +1,208 @@
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user