Show pending contacts (#547)

* capture contact connecting event

* disable navigation to not ready chat

* update "pending contact" alert, Russian translations

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
IanRDavies
2022-04-22 17:26:17 +01:00
committed by GitHub
parent 7c2edff81f
commit 1932873776
12 changed files with 233 additions and 18 deletions

View File

@@ -357,7 +357,7 @@ class Contact(
override val chatType get() = ChatType.Direct
override val id get() = "@$contactId"
override val apiId get() = contactId
override val ready get() = activeConn.connStatus == "ready" || activeConn.connStatus == "snd-ready"
override val ready get() = activeConn.connStatus == "ready"
override val displayName get() = profile.displayName
override val fullName get() = profile.fullName
override val image get() = profile.image

View File

@@ -11,7 +11,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Bolt
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import chat.simplex.app.*
@@ -339,6 +338,9 @@ open class ChatController(private val ctrl: ChatCtrl, private val ntfManager: Nt
chatModel.updateNetworkStatus(r.contact, Chat.NetworkStatus.Connected())
// NtfManager.shared.notifyContactConnected(contact)
}
is CR.ContactConnecting -> {
chatModel.updateContact(r.contact)
}
is CR.ReceivedContactRequest -> {
val contactRequest = r.contactRequest
val cInfo = ChatInfo.ContactRequest(contactRequest)
@@ -642,6 +644,7 @@ sealed class CR {
@Serializable @SerialName("userContactLinkCreated") class UserContactLinkCreated(val connReqContact: String): CR()
@Serializable @SerialName("userContactLinkDeleted") class UserContactLinkDeleted: CR()
@Serializable @SerialName("contactConnected") class ContactConnected(val contact: Contact): CR()
@Serializable @SerialName("contactConnecting") class ContactConnecting(val contact: Contact): CR()
@Serializable @SerialName("receivedContactRequest") class ReceivedContactRequest(val contactRequest: UserContactRequest): CR()
@Serializable @SerialName("acceptingContactRequest") class AcceptingContactRequest(val contact: Contact): CR()
@Serializable @SerialName("contactRequestRejected") class ContactRequestRejected: CR()
@@ -685,6 +688,7 @@ sealed class CR {
is UserContactLinkCreated -> "userContactLinkCreated"
is UserContactLinkDeleted -> "userContactLinkDeleted"
is ContactConnected -> "contactConnected"
is ContactConnecting -> "contactConnecting"
is ReceivedContactRequest -> "receivedContactRequest"
is AcceptingContactRequest -> "acceptingContactRequest"
is ContactRequestRejected -> "contactRequestRejected"
@@ -729,6 +733,7 @@ sealed class CR {
is UserContactLinkCreated -> connReqContact
is UserContactLinkDeleted -> noDetails()
is ContactConnected -> json.encodeToString(contact)
is ContactConnecting -> json.encodeToString(contact)
is ReceivedContactRequest -> json.encodeToString(contactRequest)
is AcceptingContactRequest -> json.encodeToString(contact)
is ContactRequestRejected -> noDetails()

View File

@@ -25,7 +25,11 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
if (chat.chatInfo is ChatInfo.ContactRequest) {
contactRequestAlertDialog(chat.chatInfo, chatModel)
} else {
withApi { openChat(chatModel, chat.chatInfo) }
if (chat.chatInfo.ready) {
withApi { openChat(chatModel, chat.chatInfo) }
} else {
pendingConnectionAlertDialog(chat.chatInfo, chatModel)
}
}
}
)
@@ -63,6 +67,24 @@ fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel
)
}
fun pendingConnectionAlertDialog(chatInfo: ChatInfo, chatModel: ChatModel) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.alert_title_contact_connection_pending),
text = generalGetString(R.string.alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry),
confirmText = generalGetString(R.string.button_delete_contact),
onConfirm = {
withApi {
val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId)
if (r) {
chatModel.removeChat(chatInfo.id)
chatModel.chatId.value = null
}
}
},
dismissText = generalGetString(R.string.cancel_verb),
)
}
@Composable
fun ChatListNavLinkLayout(chat: Chat, click: () -> Unit) {
Surface(

View File

@@ -9,6 +9,7 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@@ -17,8 +18,7 @@ import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.model.Chat
import chat.simplex.app.model.getTimestampText
import chat.simplex.app.ui.theme.HighOrLowlight
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.item.MarkdownText
import chat.simplex.app.views.helpers.*
@@ -36,17 +36,21 @@ fun ChatPreviewView(chat: Chat) {
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.h3,
fontWeight = FontWeight.Bold
fontWeight = FontWeight.Bold,
color = if (chat.chatInfo.ready) Color.Unspecified else HighOrLowlight
)
val ci = chat.chatItems.lastOrNull()
if (ci != null) {
MarkdownText(
ci.text, ci.formattedText, ci.memberDisplayName,
metaText = ci.timestampText,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
if (chat.chatInfo.ready) {
val ci = chat.chatItems.lastOrNull()
if (ci != null) {
MarkdownText(
ci.text, ci.formattedText, ci.memberDisplayName,
metaText = ci.timestampText,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
} else {
Text(generalGetString(R.string.contact_connection_pending), color = HighOrLowlight)
}
}
val ts = chat.chatItems.lastOrNull()?.timestampText ?: getTimestampText(chat.chatInfo.createdAt)

View File

@@ -71,6 +71,7 @@
<string name="welcome">Здравствуйте!</string>
<string name="this_text_is_available_in_settings">Этот текст можно найти в Настройках</string>
<string name="your_chats">Ваши чаты</string>
<string name="contact_connection_pending">соединяется…</string>
<!-- ComposeView.kt -->
<string name="attach">Прикрепить</string>
@@ -129,6 +130,10 @@
<string name="accept_contact_button">Принять</string>
<string name="reject_contact_button">Отклонить</string>
<!-- Connection Pending Alert Dialogue - ChatListNavLinkView.kt -->
<string name="alert_title_contact_connection_pending">Соединение еще не установлено!</string>
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">Ваш контакт должен быть в сети чтобы установить соединение.\nВы можете отменить соединение и удалить контакт (и попробовать позже с другой ссылкой).</string>
<!-- Contact Request Information - ContactRequestView.kt -->
<string name="contact_wants_to_connect_with_you">хочет соединиться с вами!</string>

View File

@@ -71,6 +71,7 @@
<string name="welcome">Welcome!</string>
<string name="this_text_is_available_in_settings">This text is available in settings</string>
<string name="your_chats">Your chats</string>
<string name="contact_connection_pending">connecting…</string>
<!-- ComposeView.kt -->
<string name="attach">Attach</string>
@@ -123,12 +124,16 @@
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 desktop: scan displayed QR code from the app, via <b>Scan QR code</b>.</string>
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app">📱 mobile: tap <b>Open in mobile app</b>, then tap <b>Connect</b> in the app.</string>
<!-- Contact Request Alert Dialogue - CharListNavLinkView.kt -->
<!-- Contact Request Alert Dialogue - ChatListNavLinkView.kt -->
<string name="accept_connection_request__question">Accept connection request?</string>
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">If you choose to reject sender will NOT be notified.</string>
<string name="accept_contact_button">Accept</string>
<string name="reject_contact_button">Reject</string>
<!-- Connection Pending Alert Dialogue - ChatListNavLinkView.kt -->
<string name="alert_title_contact_connection_pending">Contact is not connected yet!</string>
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">Your contact needs to be online for the connection to complete.\nYou can cancel this connection and remove the contact (and try later with a new link).</string>
<!-- Contact Request Information - ContactRequestView.kt -->
<string name="contact_wants_to_connect_with_you">wants to connect to you!</string>

View File

@@ -455,7 +455,7 @@ struct Contact: Identifiable, Decodable, NamedChat {
var id: ChatId { get { "@\(contactId)" } }
var apiId: Int64 { get { contactId } }
var ready: Bool { get { activeConn.connStatus == "ready" || activeConn.connStatus == "snd-ready" } }
var ready: Bool { get { activeConn.connStatus == "ready" } }
var displayName: String { get { profile.displayName } }
var fullName: String { get { profile.fullName } }
var image: String? { get { profile.image } }

View File

@@ -154,6 +154,7 @@ enum ChatResponse: Decodable, Error {
case userContactLinkCreated(connReqContact: String)
case userContactLinkDeleted
case contactConnected(contact: Contact)
case contactConnecting(contact: Contact)
case receivedContactRequest(contactRequest: UserContactRequest)
case acceptingContactRequest(contact: Contact)
case contactRequestRejected
@@ -198,6 +199,7 @@ enum ChatResponse: Decodable, Error {
case .userContactLinkCreated: return "userContactLinkCreated"
case .userContactLinkDeleted: return "userContactLinkDeleted"
case .contactConnected: return "contactConnected"
case .contactConnecting: return "contactConnecting"
case .receivedContactRequest: return "receivedContactRequest"
case .acceptingContactRequest: return "acceptingContactRequest"
case .contactRequestRejected: return "contactRequestRejected"
@@ -245,6 +247,7 @@ enum ChatResponse: Decodable, Error {
case let .userContactLinkCreated(connReq): return connReq
case .userContactLinkDeleted: return noDetails
case let .contactConnected(contact): return String(describing: contact)
case let .contactConnecting(contact): return String(describing: contact)
case let .receivedContactRequest(contactRequest): return String(describing: contactRequest)
case let .acceptingContactRequest(contact): return String(describing: contact)
case .contactRequestRejected: return noDetails
@@ -702,6 +705,8 @@ func processReceivedMsg(_ res: ChatResponse) {
chatModel.updateContact(contact)
chatModel.updateNetworkStatus(contact, .connected)
NtfManager.shared.notifyContactConnected(contact)
case let .contactConnecting(contact):
chatModel.updateContact(contact)
case let .receivedContactRequest(contactRequest):
chatModel.addChat(Chat(
chatInfo: ChatInfo.contactRequest(contactRequest: contactRequest),

View File

@@ -53,11 +53,20 @@ struct ChatListNavLink: View {
}
.swipeActions(edge: .trailing) {
Button(role: .destructive) {
AlertManager.shared.showAlert(deleteContactAlert(contact))
AlertManager.shared.showAlert(
contact.ready
? deleteContactAlert(contact)
: deletePendingContactAlert(chat, contact)
)
} label: {
Label("Delete", systemImage: "trash")
}
}
.onTapGesture {
if !contact.ready {
AlertManager.shared.showAlert(pendingContactAlert(chat, contact))
}
}
.frame(height: 80)
}
@@ -150,6 +159,41 @@ struct ChatListNavLink: View {
secondaryButton: .cancel()
)
}
private func pendingContactAlert(_ chat: Chat, _ contact: Contact) -> Alert {
Alert(
title: Text("Contact is not connected yet!"),
message: Text("Your contact needs to be online for the connection to complete.\nYou can cancel this connection and remove the contact (and try later with a new link)."),
primaryButton: .cancel(),
secondaryButton: .destructive(Text("Delete Contact")) {
removePendingContact(chat, contact)
}
)
}
private func deletePendingContactAlert(_ chat: Chat, _ contact: Contact) -> Alert {
Alert(
title: Text("Delete pending connection"),
message: Text("Your contact needs to be online for the connection to complete.\nYou can cancel this connection and remove the contact (and try later with a new link)."),
primaryButton: .destructive(Text("Delete")) {
removePendingContact(chat, contact)
},
secondaryButton: .cancel()
)
}
private func removePendingContact(_ chat: Chat, _ contact: Contact) {
Task {
do {
try await apiDeleteChat(type: chat.chatInfo.chatType, id: chat.chatInfo.apiId)
DispatchQueue.main.async {
chatModel.removeChat(contact.id)
}
} catch let error {
logger.error("ChatListNavLink.removePendingContact apiDeleteChat error: \(responseError(error))")
}
}
}
}
struct ChatListNavLink_Previews: PreviewProvider {

View File

@@ -145,6 +145,11 @@
<target>Chats</target>
<note>back button to return to chats list</note>
</trans-unit>
<trans-unit id="Check messages" xml:space="preserve">
<source>Check messages</source>
<target>Check messages</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Choose from library" xml:space="preserve">
<source>Choose from library</source>
<target>Choose from library</target>
@@ -230,6 +235,11 @@
<target>Contact is connected</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Contact is not connected yet!" xml:space="preserve">
<source>Contact is not connected yet!</source>
<target>Contact is not connected yet!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy" xml:space="preserve">
<source>Copy</source>
<target>Copy</target>
@@ -260,6 +270,11 @@
<target>Delete</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete Contact" xml:space="preserve">
<source>Delete Contact</source>
<target>Delete Contact</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete address" xml:space="preserve">
<source>Delete address</source>
<target>Delete address</target>
@@ -300,6 +315,11 @@
<target>Delete message?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection" xml:space="preserve">
<source>Delete pending connection</source>
<target>Delete pending connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Develop</target>
@@ -315,11 +335,26 @@
<target>Edit</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enable notifications? (BETA)" xml:space="preserve">
<source>Enable notifications? (BETA)</source>
<target>Enable notifications? (BETA)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter one SMP server per line:" xml:space="preserve">
<source>Enter one SMP server per line:</source>
<target>Enter one SMP server per line:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error deleting token" xml:space="preserve">
<source>Error deleting token</source>
<target>Error deleting token</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering token" xml:space="preserve">
<source>Error registering token</source>
<target>Error registering token</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving SMP servers" xml:space="preserve">
<source>Error saving SMP servers</source>
<target>Error saving SMP servers</target>
@@ -552,6 +587,13 @@ to scan from the app</target>
<target>The app can notify you when you receive messages or contact requests - please open settings to enable.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The app can receive background notifications every 20 minutes to check the new messages.&#10;*Please note*: if you confirm, your device token will be sent to SimpleX Chat notifications server." xml:space="preserve">
<source>The app can receive background notifications every 20 minutes to check the new messages.
*Please note*: if you confirm, your device token will be sent to SimpleX Chat notifications server.</source>
<target>The app can receive background notifications every 20 minutes to check the new messages.
*Please note*: if you confirm, your device token will be sent to SimpleX Chat notifications server.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The messaging and application platform 100% private by design!" xml:space="preserve">
<source>The messaging and application platform 100% private by design!</source>
<target>The messaging and application platform 100% private by design!</target>
@@ -689,6 +731,13 @@ To connect, please ask your contact to create another connection link and check
<target>Your chats</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact needs to be online for the connection to complete.&#10;You can cancel this connection and remove the contact (and try later with a new link)." xml:space="preserve">
<source>Your contact needs to be online for the connection to complete.
You can cancel this connection and remove the contact (and try later with a new link).</source>
<target>Your contact needs to be online for the connection to complete.
You can cancel this connection and remove the contact (and try later with a new link).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your profile is stored on your device and shared only with your contacts.&#10;SimpleX servers cannot see your profile." xml:space="preserve">
<source>Your profile is stored on your device and shared only with your contacts.
SimpleX servers cannot see your profile.</source>

View File

@@ -145,6 +145,11 @@
<target>Назад</target>
<note>back button to return to chats list</note>
</trans-unit>
<trans-unit id="Check messages" xml:space="preserve">
<source>Check messages</source>
<target>Проверять сообщения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Choose from library" xml:space="preserve">
<source>Choose from library</source>
<target>Выбрать из библиотеки</target>
@@ -230,6 +235,11 @@
<target>Соединение с контактом установлено</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Contact is not connected yet!" xml:space="preserve">
<source>Contact is not connected yet!</source>
<target>Соединение еще не установлено!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy" xml:space="preserve">
<source>Copy</source>
<target>Скопировать</target>
@@ -260,6 +270,11 @@
<target>Удалить</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete Contact" xml:space="preserve">
<source>Delete Contact</source>
<target>Удалить контакт</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete address" xml:space="preserve">
<source>Delete address</source>
<target>Удалить адрес</target>
@@ -300,6 +315,11 @@
<target>Удалить сообщение?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection" xml:space="preserve">
<source>Delete pending connection</source>
<target>Удалить соединение</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Для разработчиков</target>
@@ -315,11 +335,26 @@
<target>Редактировать</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enable notifications? (BETA)" xml:space="preserve">
<source>Enable notifications? (BETA)</source>
<target>Включить уведомления? (БЕТА)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter one SMP server per line:" xml:space="preserve">
<source>Enter one SMP server per line:</source>
<target>Введите SMP серверы, каждый на отдельной строке:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error deleting token" xml:space="preserve">
<source>Error deleting token</source>
<target>Ошибка удаления токена</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering token" xml:space="preserve">
<source>Error registering token</source>
<target>Ошибка регистрации токена</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving SMP servers" xml:space="preserve">
<source>Error saving SMP servers</source>
<target>Ошибка при сохранении SMP серверов</target>
@@ -551,6 +586,13 @@ to scan from the app</source>
<target>Приложение может посылать вам уведомления о сообщениях и запросах на соединение - уведомления можно включить в Настройках.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The app can receive background notifications every 20 minutes to check the new messages.&#10;*Please note*: if you confirm, your device token will be sent to SimpleX Chat notifications server." xml:space="preserve">
<source>The app can receive background notifications every 20 minutes to check the new messages.
*Please note*: if you confirm, your device token will be sent to SimpleX Chat notifications server.</source>
<target>Приложение может получать скрытые уведомления каждые 20 минут чтобы проверить новые сообщения.
*Обратите внимание*: если вы подтвердите, токен вашего устройства будет послан на сервер SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The messaging and application platform 100% private by design!" xml:space="preserve">
<source>The messaging and application platform 100% private by design!</source>
<target>Платформа для сообщений и приложений, которая защищает вашу личную информацию и безопасность.</target>
@@ -688,6 +730,13 @@ To connect, please ask your contact to create another connection link and check
<target>Ваши чаты</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact needs to be online for the connection to complete.&#10;You can cancel this connection and remove the contact (and try later with a new link)." xml:space="preserve">
<source>Your contact needs to be online for the connection to complete.
You can cancel this connection and remove the contact (and try later with a new link).</source>
<target>Ваш контакт должен быть в сети чтобы установить соединение.
Вы можете отменить соединение и удалить контакт (и попробовать позже с другой ссылкой).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your profile is stored on your device and shared only with your contacts.&#10;SimpleX servers cannot see your profile." xml:space="preserve">
<source>Your profile is stored on your device and shared only with your contacts.
SimpleX servers cannot see your profile.</source>

View File

@@ -106,6 +106,9 @@
/* back button to return to chats list */
"Chats" = "Назад";
/* No comment provided by engineer. */
"Check messages" = "Проверять сообщения";
/* No comment provided by engineer. */
"Choose from library" = "Выбрать из библиотеки";
@@ -163,6 +166,9 @@
/* notification */
"Contact is connected" = "Соединение с контактом установлено";
/* No comment provided by engineer. */
"Contact is not connected yet!" = "Соединение еще не установлено!";
/* No comment provided by engineer. */
"Copy" = "Скопировать";
@@ -190,6 +196,9 @@
/* No comment provided by engineer. */
"Delete contact" = "Удалить контакт";
/* No comment provided by engineer. */
"Delete Contact" = "Удалить контакт";
/* No comment provided by engineer. */
"Delete contact?" = "Удалить контакт?";
@@ -205,6 +214,9 @@
/* No comment provided by engineer. */
"Delete message?" = "Удалить сообщение?";
/* No comment provided by engineer. */
"Delete pending connection" = "Удалить соединение";
/* deleted chat item */
"deleted" = "удалено";
@@ -217,9 +229,18 @@
/* No comment provided by engineer. */
"Edit" = "Редактировать";
/* No comment provided by engineer. */
"Enable notifications? (BETA)" = "Включить уведомления? (БЕТА)";
/* No comment provided by engineer. */
"Enter one SMP server per line:" = "Введите SMP серверы, каждый на отдельной строке:";
/* No comment provided by engineer. */
"Error deleting token" = "Ошибка удаления токена";
/* No comment provided by engineer. */
"Error registering token" = "Ошибка регистрации токена";
/* No comment provided by engineer. */
"Error saving SMP servers" = "Ошибка при сохранении SMP серверов";
@@ -367,6 +388,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "Приложение может посылать вам уведомления о сообщениях и запросах на соединение - уведомления можно включить в Настройках.";
/* No comment provided by engineer. */
"The app can receive background notifications every 20 minutes to check the new messages.\n*Please note*: if you confirm, your device token will be sent to SimpleX Chat notifications server." = "Приложение может получать скрытые уведомления каждые 20 минут чтобы проверить новые сообщения.\n*Обратите внимание*: если вы подтвердите, токен вашего устройства будет послан на сервер SimpleX Chat.";
/* No comment provided by engineer. */
"The messaging and application platform 100% private by design!" = "Платформа для сообщений и приложений, которая защищает вашу личную информацию и безопасность.";
@@ -448,6 +472,9 @@
/* No comment provided by engineer. */
"Your chats" = "Ваши чаты";
/* No comment provided by engineer. */
"Your contact needs to be online for the connection to complete.\nYou can cancel this connection and remove the contact (and try later with a new link)." = "Ваш контакт должен быть в сети чтобы установить соединение.\nВы можете отменить соединение и удалить контакт (и попробовать позже с другой ссылкой).";
/* No comment provided by engineer. */
"Your profile is stored on your device and shared only with your contacts.\nSimpleX servers cannot see your profile." = "Ваш профиль хранится на вашем устройстве и отправляется только вашим контактам.\nSimpleX серверы не могут получить доступ к вашему профилю.";