diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatViewModel.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatViewModel.kt
index 5b4f4c7..d7dbda0 100644
--- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatViewModel.kt
+++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatViewModel.kt
@@ -1,8 +1,10 @@
package ru.daemonlord.messenger.ui.chat
+import android.content.Context
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -16,6 +18,7 @@ import kotlinx.coroutines.launch
import ru.daemonlord.messenger.core.notifications.ActiveChatTracker
import ru.daemonlord.messenger.core.notifications.NotificationDispatcher
import ru.daemonlord.messenger.core.token.TokenRepository
+import ru.daemonlord.messenger.R
import ru.daemonlord.messenger.domain.chat.repository.ChatRepository
import ru.daemonlord.messenger.domain.chat.usecase.ObserveChatUseCase
import ru.daemonlord.messenger.domain.chat.usecase.ObserveChatsUseCase
@@ -66,6 +69,7 @@ class ChatViewModel @Inject constructor(
private val activeChatTracker: ActiveChatTracker,
private val notificationDispatcher: NotificationDispatcher,
private val tokenRepository: TokenRepository,
+ @ApplicationContext private val context: Context,
) : ViewModel() {
private val chatId: Long = checkNotNull(savedStateHandle["chatId"])
@@ -133,7 +137,7 @@ class ChatViewModel @Inject constructor(
isRecordingVoice = true,
isVoiceLocked = false,
voiceRecordingDurationMs = 0L,
- voiceRecordingHint = "Slide up to lock, slide left to cancel",
+ voiceRecordingHint = context.getString(R.string.chat_voice_hint_slide),
errorMessage = null,
)
}
@@ -150,7 +154,7 @@ class ChatViewModel @Inject constructor(
if (!it.isRecordingVoice) it else {
it.copy(
isVoiceLocked = true,
- voiceRecordingHint = "Recording locked",
+ voiceRecordingHint = context.getString(R.string.chat_voice_hint_locked),
)
}
}
@@ -180,7 +184,7 @@ class ChatViewModel @Inject constructor(
isVoiceLocked = false,
voiceRecordingDurationMs = 0L,
voiceRecordingHint = null,
- errorMessage = "Voice message is too short.",
+ errorMessage = context.getString(R.string.chat_error_voice_too_short),
)
}
return
@@ -326,7 +330,7 @@ class ChatViewModel @Inject constructor(
val actionState = uiState.value.actionState
if (actionState.mode == MessageSelectionMode.MULTI) {
if (forAll) {
- _uiState.update { it.copy(errorMessage = "Delete for all is available only for single message selection.") }
+ _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_error_delete_for_all_single)) }
return
}
val selectedIds = actionState.selectedMessageIds.toList().sorted()
@@ -354,7 +358,7 @@ class ChatViewModel @Inject constructor(
}
val selected = getFocusedSelectedMessage() ?: return
if (forAll && !canDeleteForAll(selected)) {
- _uiState.update { it.copy(errorMessage = "Delete for all is available only for your own messages.") }
+ _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_error_delete_for_all_own)) }
return
}
viewModelScope.launch {
@@ -474,7 +478,7 @@ class ChatViewModel @Inject constructor(
selectedCanEdit = false,
selectedCanDeleteForAll = false,
actionState = it.actionState.clearSelection(),
- errorMessage = "Chat history cleared.",
+ errorMessage = context.getString(R.string.chat_info_history_cleared),
)
}
is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) }
@@ -560,7 +564,7 @@ class ChatViewModel @Inject constructor(
_uiState.update {
it.copy(
isSending = false,
- errorMessage = "This message can no longer be edited.",
+ errorMessage = context.getString(R.string.chat_error_edit_expired),
)
}
return@launch
@@ -572,7 +576,8 @@ class ChatViewModel @Inject constructor(
_uiState.update {
it.copy(
isSending = false,
- errorMessage = uiState.value.sendRestrictionText ?: "Sending is restricted in this chat.",
+ errorMessage = uiState.value.sendRestrictionText
+ ?: context.getString(R.string.chat_error_send_restricted),
)
}
return@launch
@@ -741,14 +746,18 @@ class ChatViewModel @Inject constructor(
val restriction = if (canSend) {
null
} else {
- "Only channel owner/admin can send messages."
+ context.getString(R.string.chat_restriction_owner_admin)
+ }
+ val chatTitle = chat.displayTitle.ifBlank {
+ context.getString(R.string.chat_title_fallback, chatId)
}
- val chatTitle = chat.displayTitle.ifBlank { "Chat #$chatId" }
val chatSubtitle = when {
- chat.type.equals("private", ignoreCase = true) && chat.counterpartIsOnline == true -> "online"
- chat.type.equals("private", ignoreCase = true) && !chat.counterpartLastSeenAt.isNullOrBlank() -> "last seen recently"
- chat.type.equals("group", ignoreCase = true) -> "group"
- chat.type.equals("channel", ignoreCase = true) -> "channel"
+ chat.type.equals("private", ignoreCase = true) && chat.counterpartIsOnline == true ->
+ context.getString(R.string.chat_status_online)
+ chat.type.equals("private", ignoreCase = true) && !chat.counterpartLastSeenAt.isNullOrBlank() ->
+ context.getString(R.string.chat_status_last_seen_recently)
+ chat.type.equals("group", ignoreCase = true) -> context.getString(R.string.chat_type_group)
+ chat.type.equals("channel", ignoreCase = true) -> context.getString(R.string.chat_type_channel)
else -> ""
}
_uiState.update {
@@ -932,32 +941,32 @@ class ChatViewModel @Inject constructor(
val state = uiState.value
val selfId = state.selfUserId
if (selfId != null && userId == selfId) {
- _uiState.update { it.copy(errorMessage = "You cannot apply this action to yourself.") }
+ _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_error_action_self)) }
return false
}
val actorRole = state.chatRole?.lowercase()
if (actorRole != "owner" && actorRole != "admin") {
- _uiState.update { it.copy(errorMessage = "You don't have enough permissions.") }
+ _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_error_permissions)) }
return false
}
if (ownerOnly && actorRole != "owner") {
- _uiState.update { it.copy(errorMessage = "Only owner can perform this action.") }
+ _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_error_owner_only)) }
return false
}
val targetRole = state.chatMembers.firstOrNull { it.userId == userId }?.role?.lowercase()
if (targetRole == "owner") {
- _uiState.update { it.copy(errorMessage = "You cannot manage owner account.") }
+ _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_error_manage_owner)) }
return false
}
if (actorRole == "admin" && (targetRole == "admin" || targetRole == "owner")) {
- _uiState.update { it.copy(errorMessage = "Admin cannot manage admins or owner.") }
+ _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_error_admin_manage_admin_owner)) }
return false
}
if (action == "transfer_ownership" && targetRole == "owner") {
- _uiState.update { it.copy(errorMessage = "Choose another member for ownership transfer.") }
+ _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_error_transfer_choose_another)) }
return false
}
return true
@@ -965,11 +974,11 @@ class ChatViewModel @Inject constructor(
private fun AppError.toUiMessage(): String {
return when (this) {
- AppError.Network -> "Network error."
- AppError.Unauthorized -> "Session expired."
- AppError.InvalidCredentials -> "Authorization error."
- is AppError.Server -> "Server error."
- is AppError.Unknown -> "Unknown error."
+ AppError.Network -> context.getString(R.string.error_network)
+ AppError.Unauthorized -> context.getString(R.string.error_session_expired)
+ AppError.InvalidCredentials -> context.getString(R.string.error_authorization)
+ is AppError.Server -> context.getString(R.string.error_server)
+ is AppError.Unknown -> context.getString(R.string.error_unknown)
}
}
diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml
index 40f0037..6ceab09 100644
--- a/android/app/src/main/res/values-ru/strings.xml
+++ b/android/app/src/main/res/values-ru/strings.xml
@@ -114,6 +114,22 @@
Забанить %1$s?
Исключить участника
Исключить %1$s из чата?
+ Голосовое сообщение слишком короткое.
+ Удаление для всех доступно только при выборе одного сообщения.
+ Удаление для всех доступно только для ваших сообщений.
+ История чата очищена.
+ Это сообщение уже нельзя редактировать.
+ Отправка сообщений в этом чате ограничена.
+ Только owner/admin канала может отправлять сообщения.
+ Это действие нельзя применить к себе.
+ Недостаточно прав.
+ Только owner может выполнить это действие.
+ Нельзя управлять аккаунтом owner.
+ Админ не может управлять админами и owner.
+ Выберите другого участника для передачи owner.
+ Проведите вверх, чтобы закрепить, и влево, чтобы отменить
+ Запись закреплена
+ Чат #%1$d
Пользователь
АККАУНТЫ
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index f1ee1d0..f9f5fd0 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -114,6 +114,22 @@
Ban %1$s?
Kick member
Kick %1$s from chat?
+ Voice message is too short.
+ Delete for all is available only for single message selection.
+ Delete for all is available only for your own messages.
+ Chat history cleared.
+ This message can no longer be edited.
+ Sending is restricted in this chat.
+ Only channel owner/admin can send messages.
+ You cannot apply this action to yourself.
+ You don\'t have enough permissions.
+ Only owner can perform this action.
+ You cannot manage owner account.
+ Admin cannot manage admins or owner.
+ Choose another member for ownership transfer.
+ Slide up to lock, slide left to cancel
+ Recording locked
+ Chat #%1$d
User
ACCOUNTS