diff --git a/README.md b/README.md
index 904f1dd2b8..a6cb204193 100644
--- a/README.md
+++ b/README.md
@@ -207,6 +207,8 @@ You can use SimpleX with your own servers and still communicate with people usin
Recent updates:
+[July 22, 2023. SimpleX Chat: v5.2 released with message delivery receipts](./blog/20230722-simplex-chat-v5-2-message-delivery-receipts.md).
+
[May 23, 2023. SimpleX Chat: v5.1 released with message reactions and self-destruct passcode](./blog/20230523-simplex-chat-v5-1-message-reactions-self-destruct-passcode.md).
[Apr 22, 2023. SimpleX Chat: vision and funding, v5.0 released with videos and files up to 1gb](./blog/20230422-simplex-chat-vision-funding-v5-videos-files-passcode.md).
@@ -337,8 +339,8 @@ Please also join [#simplex-devs](https://simplex.chat/contact#/?v=1-2&smp=smp%3A
- ✅ Message reactions
- ✅ Message editing history
- ✅ Reduced battery and traffic usage in large groups.
+- ✅ Message delivery confirmation (with sender opt-out per contact).
- 🏗 Desktop client.
-- 🏗 Message delivery confirmation (with sender opt-in or opt-out per contact, TBC).
- SMP queue redundancy and rotation (manual is supported).
- Include optional message into connection request sent via contact address.
- Local app files encryption.
diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift
index 134c9679d9..6e792e825d 100644
--- a/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift
@@ -62,6 +62,7 @@ struct CIFileView: View {
case .rcvComplete: return true
case .rcvCancelled: return false
case .rcvError: return false
+ case .invalid: return false
}
}
return false
@@ -149,6 +150,7 @@ struct CIFileView: View {
case .rcvComplete: fileIcon("doc.fill")
case .rcvCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .rcvError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
+ case .invalid: fileIcon("doc.fill", innerIcon: "questionmark", innerIconSize: 10)
}
} else {
fileIcon("doc.fill")
diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift
index a9eadc5aa2..b13ee52829 100644
--- a/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift
@@ -99,6 +99,7 @@ struct CIImageView: View {
case .rcvTransfer: progressView()
case .rcvCancelled: fileIcon("xmark", 10, 13)
case .rcvError: fileIcon("xmark", 10, 13)
+ case .invalid: fileIcon("questionmark", 10, 13)
default: EmptyView()
}
}
diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift
index 0232be700b..4387614918 100644
--- a/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift
@@ -212,6 +212,7 @@ struct CIVideoView: View {
}
case .rcvCancelled: fileIcon("xmark", 10, 13)
case .rcvError: fileIcon("xmark", 10, 13)
+ case .invalid: fileIcon("questionmark", 10, 13)
default: EmptyView()
}
}
diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIVoiceView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIVoiceView.swift
index e6ce74953b..9541ac9483 100644
--- a/apps/ios/Shared/Views/Chat/ChatItem/CIVoiceView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatItem/CIVoiceView.swift
@@ -144,6 +144,7 @@ struct VoiceMessagePlayer: View {
case .rcvComplete: playbackButton()
case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
case .rcvError: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
+ case .invalid: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
}
} else {
playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift
index 31930fd31c..cfad3cc691 100644
--- a/apps/ios/SimpleXChat/ChatTypes.swift
+++ b/apps/ios/SimpleXChat/ChatTypes.swift
@@ -2273,6 +2273,7 @@ public struct CIMeta: Decodable {
case .sndErrorAuth: return ("multiply", .red)
case .sndError: return ("exclamationmark.triangle.fill", .yellow)
case .rcvNew: return ("circlebadge.fill", Color.accentColor)
+ case .invalid: return ("questionmark", metaColor)
default: return nil
}
}
@@ -2343,6 +2344,7 @@ public enum CIStatus: Decodable {
case sndError(agentError: String)
case rcvNew
case rcvRead
+ case invalid(text: String)
var id: String {
switch self {
@@ -2353,6 +2355,7 @@ public enum CIStatus: Decodable {
case .sndError: return "sndError"
case .rcvNew: return "rcvNew"
case .rcvRead: return "rcvRead"
+ case .invalid: return "invalid"
}
}
}
@@ -2615,6 +2618,7 @@ public struct CIFile: Decodable {
case .rcvCancelled: return false
case .rcvComplete: return true
case .rcvError: return false
+ case .invalid: return false
}
}
}
@@ -2638,6 +2642,7 @@ public struct CIFile: Decodable {
case .rcvCancelled: return nil
case .rcvComplete: return nil
case .rcvError: return nil
+ case .invalid: return nil
}
}
}
@@ -2698,6 +2703,7 @@ public enum CIFileStatus: Decodable, Equatable {
case rcvComplete
case rcvCancelled
case rcvError
+ case invalid(text: String)
var id: String {
switch self {
@@ -2712,6 +2718,7 @@ public enum CIFileStatus: Decodable, Equatable {
case .rcvComplete: return "rcvComplete"
case .rcvCancelled: return "rcvCancelled"
case .rcvError: return "rcvError"
+ case .invalid: return "invalid"
}
}
}
diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/model/ChatModel.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/model/ChatModel.kt
index 1a76510a0b..5adc17fc61 100644
--- a/apps/multiplatform/android/src/main/java/chat/simplex/app/model/ChatModel.kt
+++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/model/ChatModel.kt
@@ -1626,6 +1626,7 @@ data class CIMeta (
is CIStatus.SndErrorAuth -> MR.images.ic_close to Color.Red
is CIStatus.SndError -> MR.images.ic_warning_filled to WarningYellow
is CIStatus.RcvNew -> MR.images.ic_circle_filled to primaryColor
+ is CIStatus.Invalid -> MR.images.ic_question_mark to metaColor
else -> null
}
@@ -1712,6 +1713,7 @@ sealed class CIStatus {
@Serializable @SerialName("sndError") class SndError(val agentError: String): CIStatus()
@Serializable @SerialName("rcvNew") class RcvNew: CIStatus()
@Serializable @SerialName("rcvRead") class RcvRead: CIStatus()
+ @Serializable @SerialName("invalid") class Invalid(val text: String): CIStatus()
}
@Serializable
@@ -1949,6 +1951,7 @@ class CIFile(
is CIFileStatus.RcvCancelled -> false
is CIFileStatus.RcvComplete -> true
is CIFileStatus.RcvError -> false
+ is CIFileStatus.Invalid -> false
}
@Transient
@@ -1969,6 +1972,7 @@ class CIFile(
is CIFileStatus.RcvCancelled -> null
is CIFileStatus.RcvComplete -> null
is CIFileStatus.RcvError -> null
+ is CIFileStatus.Invalid -> null
}
companion object {
@@ -2038,6 +2042,7 @@ sealed class CIFileStatus {
@Serializable @SerialName("rcvComplete") object RcvComplete: CIFileStatus()
@Serializable @SerialName("rcvCancelled") object RcvCancelled: CIFileStatus()
@Serializable @SerialName("rcvError") object RcvError: CIFileStatus()
+ @Serializable @SerialName("invalid") class Invalid(val text: String): CIFileStatus()
}
@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt
index 7c9e49766b..82ecefaf20 100644
--- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt
+++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt
@@ -170,6 +170,7 @@ fun CIFileView(
is CIFileStatus.RcvComplete -> fileIcon()
is CIFileStatus.RcvCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.RcvError -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
+ is CIFileStatus.Invalid -> fileIcon(innerIcon = painterResource(MR.images.ic_question_mark))
}
} else {
fileIcon()
diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt
index 642757f271..f5ebf4753b 100644
--- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt
+++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt
@@ -86,6 +86,7 @@ fun CIImageView(
is CIFileStatus.RcvTransfer -> progressIndicator()
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
+ is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
else -> {}
}
}
diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt
index f6123e7bed..ee8422d46d 100644
--- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt
+++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt
@@ -309,6 +309,7 @@ private fun loadingIndicator(file: CIFile?) {
}
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
+ is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
else -> {}
}
}
diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_question_mark.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_question_mark.svg
new file mode 100644
index 0000000000..9c2e7e110b
--- /dev/null
+++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_question_mark.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/blog/20230722-simplex-chat-v5-2-message-delivery-receipts.md b/blog/20230722-simplex-chat-v5-2-message-delivery-receipts.md
index 7f4514e98d..42c08245f8 100644
--- a/blog/20230722-simplex-chat-v5-2-message-delivery-receipts.md
+++ b/blog/20230722-simplex-chat-v5-2-message-delivery-receipts.md
@@ -2,10 +2,8 @@
layout: layouts/article.html
title: "SimpleX Chat v5.2 released: message delivery receipts"
date: 2023-07-22
-# image: images/20230523-reactions.png
-# imageBottom: true
-# previewBody: blog_previews/20230523.html
-preview: TODO this is a placeholder for the release announcement
+image: images/20230722-receipts-full.png
+previewBody: blog_previews/20230722.html
permalink: "/blog/20230722-simplex-chat-v5-2-message-delivery-receipts.html"
---
@@ -13,26 +11,144 @@ permalink: "/blog/20230722-simplex-chat-v5-2-message-delivery-receipts.html"
**Published:** July 22, 2023
-TODO this is a draft of the release announcement
+**What's new in v5.2:**
+- [message delivery receipts](#message-delivery-receipts) – with opt-out per contact!
+- [filter favorite and unread chats](#filter-favorite-and-unread-chats).
+- [more usable groups](#more-usable-groups):
+ - view full original replied message in info.
+ - share your address with your contacts and group members via your chat profile.
+ - search new and existing members.
+- [stability improvements](#stability-improvements):
+ - keep your connections working after restoring from backup.
+ - restart app (Android) or reconnect servers (iOS).
+ - more reliable switching of the receiving address.
+ - more stable message delivery.
+- other improvements:
+ - [better disappearing messages](#better-disappearing-messages).
+ - [prohibit message reactions](#prohibit-message-reactions).
-What's new in v5.2:
+**Platform evolution:**
+- [problems of public groups](#problems-of-public-groups):
+ - why not all messages are received.
+ - how to cope with these problems.
+ - when will public groups be more usable.
+- [what about read receipts?](#what-about-read-receipts)
-- message delivery receipts
-- improvements for groups
- - view quoted messages
- - share SimpleX address with your contacts via your chat profile
- - search for group members
-- feature allowing to fix connection encryption (for example after importing old database)
-- mark chats as favorite and filter chats
-- restart/reconnect
-- chat preference to allow/prohibit message reactions
-- disappearing messages improvements:
- - send with custom timer when allowed but not enabled in the conversation
- - increased timer limit
+## What's new in v5.2
-## Future of SimpleX Chat groups and communities
+### Message delivery receipts
-TODO
+
+
+Most messaging apps add two ticks to sent messages – the first one to show that the message is accepted by the server, and the second – that it is delivered to the recipient's device. It confirms that the network is functioning, and that the message is not lost or delayed. SimpleX Chat now has this feature too!
+
+In some cases it may compromise recipients' privacy, as they show that the recipient is online, so we made sending delivery receipts optional – it can be disabled separately for each chat profile or contact. For the new chat profiles this feature is enabled by default.
+
+To avoid compromising your privacy, sending delivery receipts is disabled for all your existing chat profiles. The first time you start the app after the update, you will be offered to enable them for all [visible profiles](./20230328-simplex-chat-v4-6-hidden-profiles.md#hidden-chat-profiles), and they can be enabled later via Privacy and Security settings.
+
+### Filter favorite and unread chats
+
+
+
+You can now mark your contacts and groups as _favorite_, to be able to find them faster. With filter enabled, you will only see favorite chats, chats that contain unread messages and also any unaccepted group invitations and contact requests.
+
+### More usable groups
+
+Active SimpleX Chat users know how broken the current group experience is, and that we plan some major overhaul of the groups protocol – more on that below. In the meanwhile, we added some simple features that make groups in their current state a bit more usable.
+
+#### What is this in reply to?
+
+
+
+A major problem is that you can see replies to the messages you've not seen before - this would happen both when you just join the group, and didn't connect to most other members, and also when other new members join the group and they didn't yet connect to you – so literally all the time, and the bigger the group gets, the worse it becomes. While this problem cannot be solved without major group protocol changes, at least there is now ability to see the original message that was replied to via the message information.
+
+#### How to connect to this member?
+
+
+
+To simplify direct connections with other group members, you can now share your SimpleX address via your chat profile, and group members can send you a contact request even if the group does not allow direct messages.
+
+#### How to find a member in the list?
+
+Large member lists (and also the long lists of contacts, if you have many of them) become hard to scroll through, so now there is a search in both lists.
+
+### Stability improvements
+
+This version fixes many long-standing problems with the message delivery, failed connections with group members (that also contributed to group fragmentation), and reduces traffic in groups (beta users experienced a traffic spike because of this fix, but it doesn't affect the final v5.2 release). It's not the end of the road to making SimpleX Chat as stable as mainstream messengers, but it is a big improvement.
+
+Please report the cases when messages are not delivered – delivery receipts should help with that.
+
+#### Messages failed to decrypt? Problem solved!
+
+Previously, a growing number of users had the issue when after restoring the chat database from backup, messages from some contacts failed to decrypt and were showing an error in the app.
+
+This happens due to double ratchet protocol protecting the integrity of end-to-end encryption after the compromise - [post-compromise security](../docs/GLOSSARY.md#post-compromise-security). The protocol logic does not allow to use the old version of the database to decrypt the message.
+
+v5.2 added the extension to the messaging protocol allowing to negotiate the new ratchet keys in such cases - both with the contacts and the group members. This requires a user action, and it resets the security code verification status for this contact or member – you need to verify it again to have the additional protection from [man-in-the-middle attacks](../docs/GLOSSARY.md#man-in-the-middle-attack).
+
+The negotiation of the new ratchet keys still happens via the end-to-end encrypted messages, as the protocol has two layers of end-to-end encryption, so it cannot be compromised by the messaging relays.
+
+You may still lose connection if you or your contact changed the receiving address after you made the backup, so make sure to make a new backup after any receiving address changes.
+
+#### Reconnect the servers
+
+While v5.2 solved many message delivery issues, there may be some others, but they are usually resolved with app restart. It was difficult to fully restart Android app, as there is a continuosly running background service for notifications that doesn't restart with the app. Now Android app has both Restart and Shutdown buttons that take background service into account.
+
+On iOS you can now pull down the list of conversations to reconnect to all relays without restarting the app.
+
+### Better disappearing messages
+
+You can now send a separate disappearing message if the chat preferences allow them, but do not have any time to disappear enabled – this applies both to groups and to contacts. You can also set the time to disappear up to 12 months.
+
+### Prohibit message reactions
+
+While most people like message reactions, some conversations make them inappropriate - you can disable them now.
+
+## Platform evolution
+
+### Problems of public groups
+
+As I wrote above, the major problem is that not all messages are received by all members, or, at least, they may be substantially delayed. Additional problems are various scenarios when the list of members gets out of sync for different members.
+
+How to cope with these problems?
+
+It really helps to only use one link shared with the members to join the group - the one created by the client that is most frequently online, ideally always online. This is sometimes confusing, as any group admin can create another group link, and share it with the members, and if this admin is not online, the new member won't be able to join.
+
+We will add new group features to manage fragmentation - there will be an option to fix the connection with the member that you failed to connect to by passing the link out-of-band. This can be particularly helpful for stable groups of 20-50 people where it's important to see all messages.
+
+In the long term, the only way to make groups usable is to move to a new design. We considered several options.
+
+#### Why not hosted groups with MLS?
+
+Initially, we considered the design with the dedicated servers, potentially self-hosted, that host groups. This design would require adopting MLS (or similar) protocol for group-wide key agreement. Unfortunately, this design is not sufficiently resilient and easier to censor than decentralized design. Also, MLS protocol is very complex to implement, requires a centralized component, and reduces forward secrecy. So we decided against this approach.
+
+#### Why not fully decentralized groups?
+
+We also [considered](../docs/rfcs/2023-05-02-groups.md) rumour-mongering protocol, where all members are equal and participate in message dissemination. The problem with this approach is that it adds a lot of traffic for all members, even those who mostly read messages. Also, it still requires establishing a fully connected graph, and with large groups it becomes prohibitively expensive and unreliable, given that many members join public groups for a limited time.
+
+#### Members host the groups
+
+We are now considering a middle-ground - the design where the owners and admins host the group, synchronising the state between them, receiving and re-broadcasting the messages between all members. This puts a higher burden on these members, but these clients can be hosted in the cloud, and also group owners have a larger incentive to maintain group integrity. At the same time, this design is better for the rest of the group members, as they don't need to establish connections with all other members, only with a limited number of "hosting" members, and it also better protects their privacy, due to the lack of direct connections between most members.
+
+This approach avoids the need for a group-wide key agreement protocol, as hosting members are expected to have access to all content anyway, so pair-wise ratchets are sufficient. At the same time the content remains end-to-end encrypted, and protected from the outsiders.
+
+This approach also simplifies moderation - the message that needs to be removed simply won't reach the members before it is moderated (in case of automatic or policy-based moderation).
+
+Discovery and content search in such groups will be provided via a dedicated discovery server that will participate in the group, provide an always-online client, and also automatic content moderation functionality - a possible approach to moderation is [described here](../docs/rfcs/2023-05-22-groups-moderation.md).
+
+We really look forward to your feedback on this design.
+
+### What about read receipts?
+
+We have an approximately equal number of users who ask us to add receipts, and those who ask not to add them, even as optional.
+
+While read receipts provide some convenience to the message senders, they introduce a lot of stress for the recipients.
+
+As one of the users in the group wrote it: "The existence of read receipts in other platforms is exhausting and is often a source of undue stress. I have to make a decision to read something and let someone know that I have read something and decided not to respond or merely didn't have the time to respond. The outcome of that is a complex social negotiation with non-theoretical social fallout as a consequence. All in all, it's an invasion of privacy of being able to read things at the pace of the individual as opposed to the pace dictated by others... Most people don't need a read receipt, so leave it to a group of individuals to decide if having read receipts make sense to them for their workflow".
+
+Also read [this post](https://neilalexander.dev/2021/04/09/read-receipts-typing-notifs) about the damage from read receipts and other invasive features, like typing and presense notifications.
+
+There is also no discounting that the presense of read receipts functionality, even as opt-in, creates a social pressure to enable them, with the same consequences – there are many scenarios when they become non-optional in some relationships. So many users belive, and we share this view, that it is better not to have these features at all. We will be re-assessing this view.
## SimpleX platform
diff --git a/blog/README.md b/blog/README.md
index 56c39589a2..129ba2c80d 100644
--- a/blog/README.md
+++ b/blog/README.md
@@ -1,5 +1,31 @@
# Blog
+July 22, 2023 [SimpleX Chat v5.2 released](./20230722-simplex-chat-v5-2-message-delivery-receipts.md)
+
+**What's new in v5.2:**
+
+- message delivery receipts – with opt-out per contact!
+- filter favorite and unread chats.
+- more usable groups:
+ - view full original replied message in info.
+ - share your address with your contacts and group members via your chat profile.
+ - search new and existing members.
+- stability improvements:
+ - keep your connections working after restoring from backup.
+ - restart app (Android) or reconnect servers (iOS).
+ - more reliable switching of the receiving address.
+ - more stable message delivery.
+- other improvements:
+ - better disappearing messages.
+ - prohibit message reactions.
+
+**Platform evolution:**
+
+- problems of public groups problems of public groups and their future.
+- what about read receipts?
+
+---
+
May 23, 2023 [SimpleX Chat v5.1 released](./20230523-simplex-chat-v5-1-message-reactions-self-destruct-passcode.md)
What's new in v5.1:
diff --git a/blog/images/20230722-filter.png b/blog/images/20230722-filter.png
new file mode 100644
index 0000000000..5845c7eb3b
Binary files /dev/null and b/blog/images/20230722-filter.png differ
diff --git a/blog/images/20230722-quoted.png b/blog/images/20230722-quoted.png
new file mode 100644
index 0000000000..d812d43691
Binary files /dev/null and b/blog/images/20230722-quoted.png differ
diff --git a/blog/images/20230722-receipts-full.png b/blog/images/20230722-receipts-full.png
new file mode 100644
index 0000000000..f1eb2be35f
Binary files /dev/null and b/blog/images/20230722-receipts-full.png differ
diff --git a/blog/images/20230722-receipts.png b/blog/images/20230722-receipts.png
new file mode 100644
index 0000000000..536216e3d0
Binary files /dev/null and b/blog/images/20230722-receipts.png differ
diff --git a/blog/images/20230722-search.png b/blog/images/20230722-search.png
new file mode 100755
index 0000000000..605d8cf51a
Binary files /dev/null and b/blog/images/20230722-search.png differ
diff --git a/package.yaml b/package.yaml
index c4dcecd981..c4ac644da3 100644
--- a/package.yaml
+++ b/package.yaml
@@ -1,5 +1,5 @@
name: simplex-chat
-version: 5.2.0.4
+version: 5.2.1.0
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
diff --git a/simplex-chat.cabal b/simplex-chat.cabal
index bba4d69689..c43adfb3e8 100644
--- a/simplex-chat.cabal
+++ b/simplex-chat.cabal
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
-version: 5.2.0.4
+version: 5.2.1.0
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat
diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs
index df8120b9cb..d5770065ef 100644
--- a/src/Simplex/Chat.hs
+++ b/src/Simplex/Chat.hs
@@ -139,9 +139,11 @@ defaultChatConfig =
_defaultSMPServers :: NonEmpty SMPServerWithAuth
_defaultSMPServers =
L.fromList
- [ "smp://1OwYGt-yqOfe2IyVHhxz3ohqo3aCCMjtB-8wn4X_aoY=@smp11.simplex.im,6ioorbm6i3yxmuoezrhjk6f6qgkc4syabh7m3so74xunb5nzr4pwgfqd.onion",
- "smp://UkMFNAXLXeAAe0beCa4w6X_zp18PwxSaSjY17BKUGXQ=@smp12.simplex.im,ie42b5weq7zdkghocs3mgxdjeuycheeqqmksntj57rmejagmg4eor5yd.onion",
- "smp://enEkec4hlR3UtKx2NMpOUK_K4ZuDxjWBO1d9Y4YXVaA=@smp14.simplex.im,aspkyu2sopsnizbyfabtsicikr2s4r3ti35jogbcekhm3fsoeyjvgrid.onion"
+ [ "smp://h--vW7ZSkXPeOUpfxlFGgauQmXNFOzGoizak7Ult7cw=@smp15.simplex.im,oauu4bgijybyhczbnxtlggo6hiubahmeutaqineuyy23aojpih3dajad.onion",
+ "smp://hejn2gVIqNU6xjtGM3OwQeuk8ZEbDXVJXAlnSBJBWUA=@smp16.simplex.im,p3ktngodzi6qrf7w64mmde3syuzrv57y55hxabqcq3l5p6oi7yzze6qd.onion",
+ "smp://ZKe4uxF4Z_aLJJOEsC-Y6hSkXgQS5-oc442JQGkyP8M=@smp17.simplex.im,ogtwfxyi3h2h5weftjjpjmxclhb5ugufa5rcyrmg7j4xlch7qsr5nuqd.onion",
+ "smp://PtsqghzQKU83kYTlQ1VKg996dW4Cw4x_bvpKmiv8uns=@smp18.simplex.im,lyqpnwbs2zqfr45jqkncwpywpbtq7jrhxnib5qddtr6npjyezuwd3nqd.onion",
+ "smp://N_McQS3F9TGoh4ER0QstUf55kGnNSd-wXfNPZ7HukcM=@smp19.simplex.im,i53bbtoqhlc365k6kxzwdp5w3cdt433s7bwh3y32rcbml2vztiyyz5id.onion"
]
_defaultNtfServers :: [NtfServer]
diff --git a/src/Simplex/Chat/Messages.hs b/src/Simplex/Chat/Messages.hs
index f2d6553a5a..7e8331b202 100644
--- a/src/Simplex/Chat/Messages.hs
+++ b/src/Simplex/Chat/Messages.hs
@@ -501,6 +501,7 @@ data CIFileStatus (d :: MsgDirection) where
CIFSRcvComplete :: CIFileStatus 'MDRcv
CIFSRcvCancelled :: CIFileStatus 'MDRcv
CIFSRcvError :: CIFileStatus 'MDRcv
+ CIFSInvalid :: {text :: Text} -> CIFileStatus 'MDSnd
deriving instance Eq (CIFileStatus d)
@@ -519,6 +520,7 @@ ciFileEnded = \case
CIFSRcvCancelled -> True
CIFSRcvComplete -> True
CIFSRcvError -> True
+ CIFSInvalid {} -> True
instance ToJSON (CIFileStatus d) where
toJSON = J.toJSON . jsonCIFileStatus
@@ -545,6 +547,7 @@ instance MsgDirectionI d => StrEncoding (CIFileStatus d) where
CIFSRcvComplete -> "rcv_complete"
CIFSRcvCancelled -> "rcv_cancelled"
CIFSRcvError -> "rcv_error"
+ CIFSInvalid {} -> "invalid"
strP = (\(AFS _ st) -> checkDirection st) <$?> strP
instance StrEncoding ACIFileStatus where
@@ -562,7 +565,7 @@ instance StrEncoding ACIFileStatus where
"rcv_complete" -> pure $ AFS SMDRcv CIFSRcvComplete
"rcv_cancelled" -> pure $ AFS SMDRcv CIFSRcvCancelled
"rcv_error" -> pure $ AFS SMDRcv CIFSRcvError
- _ -> fail "bad file status"
+ text -> pure $ AFS SMDSnd (CIFSInvalid $ safeDecodeUtf8 text)
where
progress :: (Int64 -> Int64 -> a) -> A.Parser a
progress f = f <$> num <*> num <|> pure (f 0 1)
@@ -580,6 +583,7 @@ data JSONCIFileStatus
| JCIFSRcvComplete
| JCIFSRcvCancelled
| JCIFSRcvError
+ | JCIFSInvalid {text :: Text}
deriving (Generic)
instance ToJSON JSONCIFileStatus where
@@ -599,6 +603,7 @@ jsonCIFileStatus = \case
CIFSRcvComplete -> JCIFSRcvComplete
CIFSRcvCancelled -> JCIFSRcvCancelled
CIFSRcvError -> JCIFSRcvError
+ CIFSInvalid text -> JCIFSInvalid text
aciFileStatusJSON :: JSONCIFileStatus -> ACIFileStatus
aciFileStatusJSON = \case
@@ -613,6 +618,7 @@ aciFileStatusJSON = \case
JCIFSRcvComplete -> AFS SMDRcv CIFSRcvComplete
JCIFSRcvCancelled -> AFS SMDRcv CIFSRcvCancelled
JCIFSRcvError -> AFS SMDRcv CIFSRcvError
+ JCIFSInvalid text -> AFS SMDSnd $ CIFSInvalid text
-- to conveniently read file data from db
data CIFileInfo = CIFileInfo
@@ -630,6 +636,7 @@ data CIStatus (d :: MsgDirection) where
CISSndError :: String -> CIStatus 'MDSnd
CISRcvNew :: CIStatus 'MDRcv
CISRcvRead :: CIStatus 'MDRcv
+ CISInvalid :: Text -> CIStatus 'MDSnd
deriving instance Show (CIStatus d)
@@ -654,6 +661,7 @@ instance MsgDirectionI d => StrEncoding (CIStatus d) where
CISSndError e -> "snd_error " <> encodeUtf8 (T.pack e)
CISRcvNew -> "rcv_new"
CISRcvRead -> "rcv_read"
+ CISInvalid {} -> "invalid"
strP = (\(ACIStatus _ st) -> checkDirection st) <$?> strP
instance StrEncoding ACIStatus where
@@ -667,7 +675,7 @@ instance StrEncoding ACIStatus where
"snd_error" -> ACIStatus SMDSnd . CISSndError . T.unpack . safeDecodeUtf8 <$> (A.space *> A.takeByteString)
"rcv_new" -> pure $ ACIStatus SMDRcv CISRcvNew
"rcv_read" -> pure $ ACIStatus SMDRcv CISRcvRead
- _ -> fail "bad status"
+ text -> pure $ ACIStatus SMDSnd (CISInvalid $ safeDecodeUtf8 text)
data JSONCIStatus
= JCISSndNew
@@ -677,6 +685,7 @@ data JSONCIStatus
| JCISSndError {agentError :: String}
| JCISRcvNew
| JCISRcvRead
+ | JCISInvalid {text :: Text}
deriving (Show, Generic)
instance ToJSON JSONCIStatus where
@@ -692,6 +701,7 @@ jsonCIStatus = \case
CISSndError e -> JCISSndError e
CISRcvNew -> JCISRcvNew
CISRcvRead -> JCISRcvRead
+ CISInvalid text -> JCISInvalid text
ciStatusNew :: forall d. MsgDirectionI d => CIStatus d
ciStatusNew = case msgDirection @d of
diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs
index 0b7db12f94..d079e1fccb 100644
--- a/src/Simplex/Chat/View.hs
+++ b/src/Simplex/Chat/View.hs
@@ -1360,6 +1360,7 @@ viewFileTransferStatusXFTP (AChatItem _ _ _ ChatItem {file = Just CIFile {fileId
CIFSRcvComplete -> ["receiving " <> fstr <> " complete" <> maybe "" (\fp -> ", path: " <> plain fp) filePath]
CIFSRcvCancelled -> ["receiving " <> fstr <> " cancelled"]
CIFSRcvError -> ["receiving " <> fstr <> " error"]
+ CIFSInvalid text -> [fstr <> " invalid status: " <> plain text]
where
fstr = fileTransferStr fileId fileName
viewFileTransferStatusXFTP _ = ["no file status"]
diff --git a/website/langs/en.json b/website/langs/en.json
index 5db528114d..74ea350e78 100644
--- a/website/langs/en.json
+++ b/website/langs/en.json
@@ -90,7 +90,7 @@
"simplex-unique-4-title": "You own SimpleX network",
"simplex-unique-4-overlay-1-title": "Fully decentralised — users own the SimpleX network",
"hero-overlay-card-1-p-1": "Many users asked: if SimpleX has no user identifiers, how can it know where to deliver messages?",
- "hero-overlay-card-1-p-2": "To deliver mesages, instead of user IDs used by all other platforms, SimpleX uses temporary anonymous pairwise identifiers of message queues, separate for each of your connections — there are no long term identifiers.",
+ "hero-overlay-card-1-p-2": "To deliver messages, instead of user IDs used by all other platforms, SimpleX uses temporary anonymous pairwise identifiers of message queues, separate for each of your connections — there are no long term identifiers.",
"hero-overlay-card-1-p-3": "You define which server(s) to use to receive the messages, your contacts — the servers you use to send the messages to them. Every conversation is likely to use two different servers.",
"hero-overlay-card-1-p-4": "This design prevents leaking any users' metadata on the application level. To further improve privacy and protect your IP address you can connect to messaging servers via Tor.",
"hero-overlay-card-1-p-5": "Only client devices store user profiles, contacts and groups; the messages are sent with 2-layer end-to-end encryption.",
@@ -233,4 +233,4 @@
"on-this-page": "On this page",
"back-to-top": "Back to top",
"glossary": "Glossary"
-}
\ No newline at end of file
+}
diff --git a/website/src/_includes/blog_previews/20230422.html b/website/src/_includes/blog_previews/20230422.html
index afb6cf757e..d95ef0e9ec 100644
--- a/website/src/_includes/blog_previews/20230422.html
+++ b/website/src/_includes/blog_previews/20230422.html
@@ -1,4 +1,4 @@
-
SimpleX Chat vision and funding:
v5.0 is released:
+v5.0 is released:
v5.1 is released:
+v5.1 is released:
v5.2 is released:
+ +more usable groups:
+stability improvements:
+Platform evolution:
+ +