Localize ProfileScreen labels and actions
Some checks failed
Android CI / android (push) Failing after 6m10s
Android Release / release (push) Failing after 6m47s
CI / test (push) Failing after 3m4s

This commit is contained in:
2026-03-11 21:03:55 +03:00
parent f88d9a2a36
commit e5e4fd653e
3 changed files with 58 additions and 22 deletions

View File

@@ -72,9 +72,11 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.compose.AsyncImage import coil.compose.AsyncImage
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import ru.daemonlord.messenger.R
import ru.daemonlord.messenger.ui.account.AccountViewModel import ru.daemonlord.messenger.ui.account.AccountViewModel
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import kotlin.math.max import kotlin.math.max
import androidx.compose.ui.res.stringResource
@Composable @Composable
fun ProfileRoute( fun ProfileRoute(
@@ -167,7 +169,7 @@ fun ProfileScreen(
if (avatarUrl.isNotBlank()) { if (avatarUrl.isNotBlank()) {
AsyncImage( AsyncImage(
model = avatarUrl, model = avatarUrl,
contentDescription = "Avatar", contentDescription = stringResource(id = R.string.profile_avatar_content_description),
modifier = Modifier modifier = Modifier
.size(108.dp) .size(108.dp)
.clip(CircleShape) .clip(CircleShape)
@@ -190,28 +192,32 @@ fun ProfileScreen(
} }
Text( Text(
text = if (name.isBlank()) "User" else name, text = if (name.isBlank()) stringResource(id = R.string.profile_user_fallback) else name,
style = MaterialTheme.typography.headlineSmall, style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onPrimaryContainer, color = MaterialTheme.colorScheme.onPrimaryContainer,
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
) )
Text("online", color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.8f), style = MaterialTheme.typography.bodyLarge) Text(
stringResource(id = R.string.chat_status_online),
color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.8f),
style = MaterialTheme.typography.bodyLarge,
)
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp),
) { ) {
HeroActionButton( HeroActionButton(
label = "Choose photo", label = stringResource(id = R.string.profile_choose_photo),
icon = Icons.Filled.AddAPhoto, icon = Icons.Filled.AddAPhoto,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
) { ) {
pickAvatarLauncher.launch("image/*") pickAvatarLauncher.launch("image/*")
} }
HeroActionButton( HeroActionButton(
label = "Edit", label = stringResource(id = R.string.profile_edit),
icon = Icons.Filled.Edit, icon = Icons.Filled.Edit,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
) { ) {
@@ -240,10 +246,14 @@ fun ProfileScreen(
.padding(16.dp), .padding(16.dp),
verticalArrangement = Arrangement.spacedBy(14.dp), verticalArrangement = Arrangement.spacedBy(14.dp),
) { ) {
ProfileInfoRow("Email", profile?.email.orEmpty()) val notSet = stringResource(id = R.string.profile_not_set)
ProfileInfoRow("Bio", bio.ifBlank { "Not set" }) ProfileInfoRow(stringResource(id = R.string.auth_label_email), profile?.email.orEmpty())
ProfileInfoRow("Username", if (username.isBlank()) "Not set" else "@$username") ProfileInfoRow(stringResource(id = R.string.profile_bio), bio.ifBlank { notSet })
ProfileInfoRow("Name", name.ifBlank { "Not set" }) ProfileInfoRow(
stringResource(id = R.string.auth_label_username),
if (username.isBlank()) notSet else "@$username",
)
ProfileInfoRow(stringResource(id = R.string.auth_label_name), name.ifBlank { notSet })
} }
} }
} }
@@ -262,9 +272,9 @@ fun ProfileScreen(
.padding(16.dp), .padding(16.dp),
verticalArrangement = Arrangement.spacedBy(10.dp), verticalArrangement = Arrangement.spacedBy(10.dp),
) { ) {
Text("Edit profile", style = MaterialTheme.typography.titleMedium) Text(stringResource(id = R.string.profile_edit_profile), style = MaterialTheme.typography.titleMedium)
HeroActionButton( HeroActionButton(
label = "Choose photo", label = stringResource(id = R.string.profile_choose_photo),
icon = Icons.Filled.AddAPhoto, icon = Icons.Filled.AddAPhoto,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) { ) {
@@ -273,30 +283,30 @@ fun ProfileScreen(
OutlinedTextField( OutlinedTextField(
value = name, value = name,
onValueChange = { name = it }, onValueChange = { name = it },
label = { Text("Name") }, label = { Text(stringResource(id = R.string.auth_label_name)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
OutlinedTextField( OutlinedTextField(
value = username, value = username,
onValueChange = { username = it }, onValueChange = { username = it },
label = { Text("Username") }, label = { Text(stringResource(id = R.string.auth_label_username)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
OutlinedTextField( OutlinedTextField(
value = bio, value = bio,
onValueChange = { bio = it }, onValueChange = { bio = it },
label = { Text("Bio") }, label = { Text(stringResource(id = R.string.profile_bio)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
OutlinedTextField( OutlinedTextField(
value = avatarUrl, value = avatarUrl,
onValueChange = { avatarUrl = it }, onValueChange = { avatarUrl = it },
label = { Text("Avatar URL") }, label = { Text(stringResource(id = R.string.profile_avatar_url)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
TextButton(onClick = { editMode = false }, modifier = Modifier.weight(1f)) { TextButton(onClick = { editMode = false }, modifier = Modifier.weight(1f)) {
Text("Cancel") Text(stringResource(id = R.string.common_cancel))
} }
Button( Button(
onClick = { onClick = {
@@ -311,7 +321,7 @@ fun ProfileScreen(
enabled = !state.isSaving && name.isNotBlank() && username.isNotBlank(), enabled = !state.isSaving && name.isNotBlank() && username.isNotBlank(),
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
) { ) {
Text("Save") Text(stringResource(id = R.string.common_save))
} }
} }
if (state.isSaving) { if (state.isSaving) {
@@ -421,7 +431,7 @@ private fun AvatarCropDialog(
.padding(16.dp), .padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp), verticalArrangement = Arrangement.spacedBy(12.dp),
) { ) {
Text("Crop avatar", style = MaterialTheme.typography.titleMedium) Text(stringResource(id = R.string.profile_crop_avatar), style = MaterialTheme.typography.titleMedium)
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -441,7 +451,7 @@ private fun AvatarCropDialog(
) { ) {
androidx.compose.foundation.Image( androidx.compose.foundation.Image(
bitmap = bitmap.asImageBitmap(), bitmap = bitmap.asImageBitmap(),
contentDescription = "Avatar crop preview", contentDescription = stringResource(id = R.string.profile_avatar_crop_preview),
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -458,7 +468,7 @@ private fun AvatarCropDialog(
onClick = onDismiss, onClick = onDismiss,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
) { ) {
Text("Cancel") Text(stringResource(id = R.string.common_cancel))
} }
Button( Button(
onClick = { onClick = {
@@ -487,11 +497,11 @@ private fun AvatarCropDialog(
}, },
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
) { ) {
Text("Use") Text(stringResource(id = R.string.profile_use_crop))
} }
} }
Text( Text(
text = "Use two fingers to zoom and move.", text = stringResource(id = R.string.profile_crop_hint),
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
) )

View File

@@ -75,7 +75,20 @@
<string name="common_delete">Удалить</string> <string name="common_delete">Удалить</string>
<string name="common_create">Создать</string> <string name="common_create">Создать</string>
<string name="common_send">Отправить</string> <string name="common_send">Отправить</string>
<string name="common_save">Сохранить</string>
<string name="common_unknown_user">Неизвестный пользователь</string> <string name="common_unknown_user">Неизвестный пользователь</string>
<string name="profile_avatar_content_description">Аватар</string>
<string name="profile_user_fallback">Пользователь</string>
<string name="profile_choose_photo">Выбрать фото</string>
<string name="profile_edit">Редактировать</string>
<string name="profile_bio">О себе</string>
<string name="profile_not_set">Не указано</string>
<string name="profile_edit_profile">Редактировать профиль</string>
<string name="profile_avatar_url">URL аватара</string>
<string name="profile_crop_avatar">Обрезать аватар</string>
<string name="profile_avatar_crop_preview">Предпросмотр обрезки аватара</string>
<string name="profile_use_crop">Использовать</string>
<string name="profile_crop_hint">Используйте два пальца для масштабирования и перемещения.</string>
<string name="chat_menu_notifications">Уведомления</string> <string name="chat_menu_notifications">Уведомления</string>
<string name="chat_menu_search">Поиск</string> <string name="chat_menu_search">Поиск</string>

View File

@@ -75,7 +75,20 @@
<string name="common_delete">Delete</string> <string name="common_delete">Delete</string>
<string name="common_create">Create</string> <string name="common_create">Create</string>
<string name="common_send">Send</string> <string name="common_send">Send</string>
<string name="common_save">Save</string>
<string name="common_unknown_user">Unknown user</string> <string name="common_unknown_user">Unknown user</string>
<string name="profile_avatar_content_description">Avatar</string>
<string name="profile_user_fallback">User</string>
<string name="profile_choose_photo">Choose photo</string>
<string name="profile_edit">Edit</string>
<string name="profile_bio">Bio</string>
<string name="profile_not_set">Not set</string>
<string name="profile_edit_profile">Edit profile</string>
<string name="profile_avatar_url">Avatar URL</string>
<string name="profile_crop_avatar">Crop avatar</string>
<string name="profile_avatar_crop_preview">Avatar crop preview</string>
<string name="profile_use_crop">Use</string>
<string name="profile_crop_hint">Use two fingers to zoom and move.</string>
<string name="chat_menu_notifications">Notifications</string> <string name="chat_menu_notifications">Notifications</string>
<string name="chat_menu_search">Search</string> <string name="chat_menu_search">Search</string>