diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt
index eec3f1d9ff..6f3376cd29 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt
@@ -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
diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
index 14ed6cd63e..bc126724b1 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
@@ -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()
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt
index f707e62c8b..b764c8d5a4 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt
@@ -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(
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt
index 3c9a4158b2..f71a0ff00b 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt
@@ -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)
diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml
index ddabcdea50..f4a36949b7 100644
--- a/apps/android/app/src/main/res/values-ru/strings.xml
+++ b/apps/android/app/src/main/res/values-ru/strings.xml
@@ -71,6 +71,7 @@
Здравствуйте!Этот текст можно найти в НастройкахВаши чаты
+ соединяется…Прикрепить
@@ -129,6 +130,10 @@
ПринятьОтклонить
+
+ Соединение еще не установлено!
+ Ваш контакт должен быть в сети чтобы установить соединение.\nВы можете отменить соединение и удалить контакт (и попробовать позже с другой ссылкой).
+
хочет соединиться с вами!
diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml
index 30ed858e2c..cbc0bd7183 100644
--- a/apps/android/app/src/main/res/values/strings.xml
+++ b/apps/android/app/src/main/res/values/strings.xml
@@ -71,6 +71,7 @@
Welcome!This text is available in settingsYour chats
+ connecting…Attach
@@ -123,12 +124,16 @@
💻 desktop: scan displayed QR code from the app, via Scan QR code.📱 mobile: tap Open in mobile app, then tap Connect in the app.
-
+
Accept connection request?If you choose to reject sender will NOT be notified.AcceptReject
+
+ Contact is not connected yet!
+ 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).
+
wants to connect to you!
diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift
index 776692b913..a2846d825a 100644
--- a/apps/ios/Shared/Model/ChatModel.swift
+++ b/apps/ios/Shared/Model/ChatModel.swift
@@ -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 } }
diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift
index 4bf008600a..e62b7e6d21 100644
--- a/apps/ios/Shared/Model/SimpleXAPI.swift
+++ b/apps/ios/Shared/Model/SimpleXAPI.swift
@@ -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),
diff --git a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift
index d25ffafe53..6689d8f5db 100644
--- a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift
+++ b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift
@@ -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 {
diff --git a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff
index 3c41816622..a76bc6a379 100644
--- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff
+++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff
@@ -145,6 +145,11 @@
Chatsback button to return to chats list
+
+ Check messages
+ Check messages
+ No comment provided by engineer.
+ Choose from libraryChoose from library
@@ -230,6 +235,11 @@
Contact is connectednotification
+
+ Contact is not connected yet!
+ Contact is not connected yet!
+ No comment provided by engineer.
+ CopyCopy
@@ -260,6 +270,11 @@
DeleteNo comment provided by engineer.
+
+ Delete Contact
+ Delete Contact
+ No comment provided by engineer.
+ Delete addressDelete address
@@ -300,6 +315,11 @@
Delete message?No comment provided by engineer.
+
+ Delete pending connection
+ Delete pending connection
+ No comment provided by engineer.
+ DevelopDevelop
@@ -315,11 +335,26 @@
EditNo comment provided by engineer.
+
+ Enable notifications? (BETA)
+ Enable notifications? (BETA)
+ No comment provided by engineer.
+ Enter one SMP server per line:Enter one SMP server per line:No comment provided by engineer.
+
+ Error deleting token
+ Error deleting token
+ No comment provided by engineer.
+
+
+ Error registering token
+ Error registering token
+ No comment provided by engineer.
+ Error saving SMP serversError saving SMP servers
@@ -552,6 +587,13 @@ to scan from the app
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.
+*Please note*: if you confirm, your device token will be sent to SimpleX Chat notifications server.
+ 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.
+ No comment provided by engineer.
+ The messaging and application platform 100% private by design!The messaging and application platform 100% private by design!
@@ -689,6 +731,13 @@ To connect, please ask your contact to create another connection link and check
Your chatsNo comment provided by engineer.
+
+ 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).
+ 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).
+ No comment provided by engineer.
+ Your profile is stored on your device and shared only with your contacts.
SimpleX servers cannot see your profile.
diff --git a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff
index 377d0b05ec..60d98f3542 100644
--- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff
+++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff
@@ -145,6 +145,11 @@
Назадback button to return to chats list
+
+ Check messages
+ Проверять сообщения
+ No comment provided by engineer.
+ Choose from libraryВыбрать из библиотеки
@@ -230,6 +235,11 @@
Соединение с контактом установленоnotification
+
+ Contact is not connected yet!
+ Соединение еще не установлено!
+ No comment provided by engineer.
+ CopyСкопировать
@@ -260,6 +270,11 @@
УдалитьNo comment provided by engineer.
+
+ Delete Contact
+ Удалить контакт
+ No comment provided by engineer.
+ Delete addressУдалить адрес
@@ -300,6 +315,11 @@
Удалить сообщение?No comment provided by engineer.
+
+ Delete pending connection
+ Удалить соединение
+ No comment provided by engineer.
+ DevelopДля разработчиков
@@ -315,11 +335,26 @@
Редактировать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 серверов
@@ -551,6 +586,13 @@ to scan from the app
Приложение может посылать вам уведомления о сообщениях и запросах на соединение - уведомления можно включить в Настройках.No comment provided by engineer.
+
+ 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.
+ Приложение может получать скрытые уведомления каждые 20 минут чтобы проверить новые сообщения.
+*Обратите внимание*: если вы подтвердите, токен вашего устройства будет послан на сервер SimpleX Chat.
+ No comment provided by engineer.
+ The messaging and application platform 100% private by design!Платформа для сообщений и приложений, которая защищает вашу личную информацию и безопасность.
@@ -688,6 +730,13 @@ To connect, please ask your contact to create another connection link and check
Ваши чатыNo comment provided by engineer.
+
+ 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).
+ Ваш контакт должен быть в сети чтобы установить соединение.
+Вы можете отменить соединение и удалить контакт (и попробовать позже с другой ссылкой).
+ No comment provided by engineer.
+ Your profile is stored on your device and shared only with your contacts.
SimpleX servers cannot see your profile.
diff --git a/apps/ios/ru.lproj/Localizable.strings b/apps/ios/ru.lproj/Localizable.strings
index e5ec985260..30fdf466bd 100644
--- a/apps/ios/ru.lproj/Localizable.strings
+++ b/apps/ios/ru.lproj/Localizable.strings
@@ -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 серверы не могут получить доступ к вашему профилю.";