Localize contacts screen and contact errors/messages (EN/RU)
This commit is contained in:
@@ -30,12 +30,14 @@ import androidx.compose.runtime.snapshotFlow
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import ru.daemonlord.messenger.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ContactsRoute(
|
fun ContactsRoute(
|
||||||
@@ -104,7 +106,7 @@ private fun ContactsScreen(
|
|||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("Contacts") },
|
title = { Text(stringResource(id = R.string.contacts_title)) },
|
||||||
)
|
)
|
||||||
PullToRefreshBox(
|
PullToRefreshBox(
|
||||||
isRefreshing = state.isRefreshing,
|
isRefreshing = state.isRefreshing,
|
||||||
@@ -122,7 +124,7 @@ private fun ContactsScreen(
|
|||||||
onValueChange = onQueryChanged,
|
onValueChange = onQueryChanged,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
label = { Text("Search contacts/users") },
|
label = { Text(stringResource(id = R.string.contacts_search_label)) },
|
||||||
)
|
)
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@@ -134,10 +136,10 @@ private fun ContactsScreen(
|
|||||||
onValueChange = onAddByEmailChanged,
|
onValueChange = onAddByEmailChanged,
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
label = { Text("Add by email") },
|
label = { Text(stringResource(id = R.string.contacts_add_by_email_label)) },
|
||||||
)
|
)
|
||||||
Button(onClick = onAddContactByEmail) {
|
Button(onClick = onAddContactByEmail) {
|
||||||
Text("Add")
|
Text(stringResource(id = R.string.common_create))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +174,7 @@ private fun ContactsScreen(
|
|||||||
if (state.isSearchingUsers || state.query.trim().length >= 2) {
|
if (state.isSearchingUsers || state.query.trim().length >= 2) {
|
||||||
item(key = "search_header") {
|
item(key = "search_header") {
|
||||||
Text(
|
Text(
|
||||||
text = "Search results",
|
text = stringResource(id = R.string.contacts_search_results),
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
)
|
)
|
||||||
@@ -197,7 +199,7 @@ private fun ContactsScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
OutlinedButton(onClick = { onAddContact(user.id) }) {
|
OutlinedButton(onClick = { onAddContact(user.id) }) {
|
||||||
Text("Add")
|
Text(stringResource(id = R.string.common_create))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +207,7 @@ private fun ContactsScreen(
|
|||||||
|
|
||||||
item(key = "contacts_header") {
|
item(key = "contacts_header") {
|
||||||
Text(
|
Text(
|
||||||
text = "My contacts",
|
text = stringResource(id = R.string.contacts_my_contacts),
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
modifier = Modifier.padding(top = 4.dp),
|
modifier = Modifier.padding(top = 4.dp),
|
||||||
@@ -226,13 +228,13 @@ private fun ContactsScreen(
|
|||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = contact.username?.let { "@$it" } ?: "last seen recently",
|
text = contact.username?.let { "@$it" } ?: stringResource(id = R.string.contacts_last_seen_recently),
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
OutlinedButton(onClick = { onRemoveContact(contact.id) }) {
|
OutlinedButton(onClick = { onRemoveContact(contact.id) }) {
|
||||||
Text("Remove")
|
Text(stringResource(id = R.string.contacts_remove))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,7 +242,7 @@ private fun ContactsScreen(
|
|||||||
if (state.contacts.isEmpty()) {
|
if (state.contacts.isEmpty()) {
|
||||||
item(key = "empty_contacts") {
|
item(key = "empty_contacts") {
|
||||||
Text(
|
Text(
|
||||||
text = "No contacts yet.",
|
text = stringResource(id = R.string.contacts_empty),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package ru.daemonlord.messenger.ui.contacts
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import android.content.Context
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -10,6 +12,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.daemonlord.messenger.R
|
||||||
import ru.daemonlord.messenger.domain.account.repository.AccountRepository
|
import ru.daemonlord.messenger.domain.account.repository.AccountRepository
|
||||||
import ru.daemonlord.messenger.domain.common.AppError
|
import ru.daemonlord.messenger.domain.common.AppError
|
||||||
import ru.daemonlord.messenger.domain.common.AppResult
|
import ru.daemonlord.messenger.domain.common.AppResult
|
||||||
@@ -18,6 +21,7 @@ import javax.inject.Inject
|
|||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class ContactsViewModel @Inject constructor(
|
class ContactsViewModel @Inject constructor(
|
||||||
private val accountRepository: AccountRepository,
|
private val accountRepository: AccountRepository,
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _uiState = MutableStateFlow(ContactsUiState())
|
private val _uiState = MutableStateFlow(ContactsUiState())
|
||||||
@@ -76,7 +80,7 @@ class ContactsViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
when (val result = accountRepository.addContact(userId = userId)) {
|
when (val result = accountRepository.addContact(userId = userId)) {
|
||||||
is AppResult.Success -> {
|
is AppResult.Success -> {
|
||||||
_uiState.update { it.copy(infoMessage = "Contact added.") }
|
_uiState.update { it.copy(infoMessage = context.getString(R.string.contacts_info_added)) }
|
||||||
loadContacts(forceRefresh = true)
|
loadContacts(forceRefresh = true)
|
||||||
}
|
}
|
||||||
is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) }
|
is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) }
|
||||||
@@ -87,7 +91,7 @@ class ContactsViewModel @Inject constructor(
|
|||||||
fun addContactByEmail() {
|
fun addContactByEmail() {
|
||||||
val email = uiState.value.addByEmail.trim()
|
val email = uiState.value.addByEmail.trim()
|
||||||
if (email.isBlank()) {
|
if (email.isBlank()) {
|
||||||
_uiState.update { it.copy(errorMessage = "Email is required.") }
|
_uiState.update { it.copy(errorMessage = context.getString(R.string.contacts_error_email_required)) }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@@ -96,7 +100,7 @@ class ContactsViewModel @Inject constructor(
|
|||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
addByEmail = "",
|
addByEmail = "",
|
||||||
infoMessage = "Contact added by email.",
|
infoMessage = context.getString(R.string.contacts_info_added_by_email),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
loadContacts(forceRefresh = true)
|
loadContacts(forceRefresh = true)
|
||||||
@@ -110,7 +114,7 @@ class ContactsViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
when (val result = accountRepository.removeContact(userId = userId)) {
|
when (val result = accountRepository.removeContact(userId = userId)) {
|
||||||
is AppResult.Success -> {
|
is AppResult.Success -> {
|
||||||
_uiState.update { it.copy(infoMessage = "Contact removed.") }
|
_uiState.update { it.copy(infoMessage = context.getString(R.string.contacts_info_removed)) }
|
||||||
loadContacts(forceRefresh = true)
|
loadContacts(forceRefresh = true)
|
||||||
}
|
}
|
||||||
is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) }
|
is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) }
|
||||||
@@ -148,11 +152,11 @@ class ContactsViewModel @Inject constructor(
|
|||||||
|
|
||||||
private fun AppError.toUiMessage(): String {
|
private fun AppError.toUiMessage(): String {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
AppError.Network -> "Network error."
|
AppError.Network -> context.getString(R.string.error_network)
|
||||||
AppError.Unauthorized -> "Session expired."
|
AppError.Unauthorized -> context.getString(R.string.error_session_expired)
|
||||||
AppError.InvalidCredentials -> "Authorization error."
|
AppError.InvalidCredentials -> context.getString(R.string.error_authorization)
|
||||||
is AppError.Server -> this.message ?: "Server error."
|
is AppError.Server -> this.message ?: context.getString(R.string.error_server)
|
||||||
is AppError.Unknown -> this.cause?.message ?: "Unknown error."
|
is AppError.Unknown -> this.cause?.message ?: context.getString(R.string.error_unknown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,4 +208,22 @@
|
|||||||
<string name="auth_send_reset_link">Отправить ссылку сброса</string>
|
<string name="auth_send_reset_link">Отправить ссылку сброса</string>
|
||||||
<string name="auth_new_password">Новый пароль</string>
|
<string name="auth_new_password">Новый пароль</string>
|
||||||
<string name="auth_reset_with_token">Сбросить по токену</string>
|
<string name="auth_reset_with_token">Сбросить по токену</string>
|
||||||
|
|
||||||
|
<string name="contacts_title">Контакты</string>
|
||||||
|
<string name="contacts_search_label">Поиск контактов/пользователей</string>
|
||||||
|
<string name="contacts_add_by_email_label">Добавить по email</string>
|
||||||
|
<string name="contacts_search_results">Результаты поиска</string>
|
||||||
|
<string name="contacts_my_contacts">Мои контакты</string>
|
||||||
|
<string name="contacts_last_seen_recently">был(а) недавно</string>
|
||||||
|
<string name="contacts_remove">Удалить</string>
|
||||||
|
<string name="contacts_empty">Контактов пока нет.</string>
|
||||||
|
<string name="contacts_info_added">Контакт добавлен.</string>
|
||||||
|
<string name="contacts_info_added_by_email">Контакт добавлен по email.</string>
|
||||||
|
<string name="contacts_info_removed">Контакт удален.</string>
|
||||||
|
<string name="contacts_error_email_required">Требуется email.</string>
|
||||||
|
<string name="error_network">Ошибка сети.</string>
|
||||||
|
<string name="error_session_expired">Сессия истекла.</string>
|
||||||
|
<string name="error_authorization">Ошибка авторизации.</string>
|
||||||
|
<string name="error_server">Ошибка сервера.</string>
|
||||||
|
<string name="error_unknown">Неизвестная ошибка.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -208,4 +208,22 @@
|
|||||||
<string name="auth_send_reset_link">Send reset link</string>
|
<string name="auth_send_reset_link">Send reset link</string>
|
||||||
<string name="auth_new_password">New password</string>
|
<string name="auth_new_password">New password</string>
|
||||||
<string name="auth_reset_with_token">Reset with token</string>
|
<string name="auth_reset_with_token">Reset with token</string>
|
||||||
|
|
||||||
|
<string name="contacts_title">Contacts</string>
|
||||||
|
<string name="contacts_search_label">Search contacts/users</string>
|
||||||
|
<string name="contacts_add_by_email_label">Add by email</string>
|
||||||
|
<string name="contacts_search_results">Search results</string>
|
||||||
|
<string name="contacts_my_contacts">My contacts</string>
|
||||||
|
<string name="contacts_last_seen_recently">last seen recently</string>
|
||||||
|
<string name="contacts_remove">Remove</string>
|
||||||
|
<string name="contacts_empty">No contacts yet.</string>
|
||||||
|
<string name="contacts_info_added">Contact added.</string>
|
||||||
|
<string name="contacts_info_added_by_email">Contact added by email.</string>
|
||||||
|
<string name="contacts_info_removed">Contact removed.</string>
|
||||||
|
<string name="contacts_error_email_required">Email is required.</string>
|
||||||
|
<string name="error_network">Network error.</string>
|
||||||
|
<string name="error_session_expired">Session expired.</string>
|
||||||
|
<string name="error_authorization">Authorization error.</string>
|
||||||
|
<string name="error_server">Server error.</string>
|
||||||
|
<string name="error_unknown">Unknown error.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user