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