From 122387d180322b06513393fc145b59e9e8f2038a Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:11:26 +0000 Subject: [PATCH 01/19] android, desktop: fix loading chat items when search was not empty (#4802) --- .../commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index a4fe622a6f..c8ad89609d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -86,6 +86,7 @@ fun ChatView(staleChatId: State, onComposed: suspend (chatId: String) - .collect { chatId -> markUnreadChatAsRead(chatId) showSearch.value = false + searchText.value = "" selectedChatItems.value = null } } From a9ec1f9ec1f1fbf8f196771d9ad88ec298464699 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Fri, 30 Aug 2024 13:39:35 +0100 Subject: [PATCH 02/19] core: 6.0.4.0 (simplexmq 6.0.3.0) --- cabal.project | 2 +- package.yaml | 2 +- scripts/nix/sha256map.nix | 2 +- simplex-chat.cabal | 2 +- src/Simplex/Chat.hs | 2 +- tests/ChatClient.hs | 1 + tests/ProtocolTests.hs | 4 ++-- 7 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cabal.project b/cabal.project index 9bf39c2841..d7f6b67eb1 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 56986f82c89b04beae84a61208db8b55eb0098e3 + tag: d559a66145cf7b4cd367c09974ed1ce8393940b2 source-repository-package type: git diff --git a/package.yaml b/package.yaml index 090933594d..947589acd0 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: simplex-chat -version: 6.0.3.0 +version: 6.0.4.0 #synopsis: #description: homepage: https://github.com/simplex-chat/simplex-chat#readme diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 0569199515..0f6592086f 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."56986f82c89b04beae84a61208db8b55eb0098e3" = "0vqvdnm560xrfq7kjsghdbpk67vn4hcdpp58dfqgh9l2c9f79bin"; + "https://github.com/simplex-chat/simplexmq.git"."d559a66145cf7b4cd367c09974ed1ce8393940b2" = "1jav7jmriims6vlkxg8gmal03f9mbgrwc8v6g0rp95ivkx8gfjyw"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 877bec0af6..b3cde5ae9f 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: 6.0.3.0 +version: 6.0.4.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 ac1d0ac601..cfc9f0dc97 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -3522,7 +3522,7 @@ agentSubscriber = do toView' $ CRChatError Nothing $ ChatErrorAgent (CRITICAL True $ "Message reception stopped: " <> show e) Nothing E.throwIO e where - process :: (ACorrId, EntityId, AEvt) -> CM' () + process :: (ACorrId, AEntityId, AEvt) -> CM' () process (corrId, entId, AEvt e msg) = run $ case e of SAENone -> processAgentMessageNoConn msg SAEConn -> processAgentMessage corrId entId msg diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs index e3d557166b..42c12f1c6e 100644 --- a/tests/ChatClient.hs +++ b/tests/ChatClient.hs @@ -442,6 +442,7 @@ smpServerCfg = logStatsStartTime = 0, serverStatsLogFile = "tests/smp-server-stats.daily.log", serverStatsBackupFile = Nothing, + pendingENDInterval = 500000, smpServerVRange = supportedServerSMPRelayVRange, transportConfig = defaultTransportServerConfig {alpn = Just supportedSMPHandshakes}, smpHandshakeTimeout = 1000000, diff --git a/tests/ProtocolTests.hs b/tests/ProtocolTests.hs index d9552452cd..f64efe108f 100644 --- a/tests/ProtocolTests.hs +++ b/tests/ProtocolTests.hs @@ -16,7 +16,7 @@ import Simplex.Chat.Types.Shared import Simplex.Messaging.Agent.Protocol import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Crypto.Ratchet -import Simplex.Messaging.Protocol (supportedSMPClientVRange) +import Simplex.Messaging.Protocol (EntityId (..), supportedSMPClientVRange) import Simplex.Messaging.ServiceScheme import Simplex.Messaging.Version import Test.Hspec @@ -33,7 +33,7 @@ queue = supportedSMPClientVRange SMPQueueAddress { smpServer = srv, - senderId = "\223\142z\251", + senderId = EntityId "\223\142z\251", dhPublicKey = "MCowBQYDK2VuAyEAjiswwI3O/NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o=", sndSecure = False } From 9432a5e5cdc56a787196d7f31c17b7efa26f340b Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Fri, 30 Aug 2024 17:09:49 +0100 Subject: [PATCH 03/19] ios: update core library --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 48 +++++++++++++--------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 1a348fc93e..b49e8ffd11 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -214,11 +214,11 @@ D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; }; D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; }; E51CC1E62C62085600DB91FE /* OneHandUICard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51CC1E52C62085600DB91FE /* OneHandUICard.swift */; }; - E51ED5A82C7F5F4B009F2C7C /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5A32C7F5F4B009F2C7C /* libgmpxx.a */; }; - E51ED5A92C7F5F4B009F2C7C /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5A42C7F5F4B009F2C7C /* libffi.a */; }; - E51ED5AA2C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5A52C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5.a */; }; - E51ED5AB2C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5A62C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5-ghc9.6.3.a */; }; - E51ED5AC2C7F5F4B009F2C7C /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5A72C7F5F4B009F2C7C /* libgmp.a */; }; + E5BD844D2C8220D0008C24D1 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD84482C8220D0008C24D1 /* libffi.a */; }; + E5BD844E2C8220D0008C24D1 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD84492C8220D0008C24D1 /* libgmpxx.a */; }; + E5BD844F2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD844A2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob-ghc9.6.3.a */; }; + E5BD84502C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD844B2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob.a */; }; + E5BD84512C8220D0008C24D1 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD844C2C8220D0008C24D1 /* libgmp.a */; }; E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; }; E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; }; E5DCF9842C5902CE007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF9822C5902CE007928CC /* Localizable.strings */; }; @@ -550,11 +550,11 @@ D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; }; D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; E51CC1E52C62085600DB91FE /* OneHandUICard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneHandUICard.swift; sourceTree = ""; }; - E51ED5A32C7F5F4B009F2C7C /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - E51ED5A42C7F5F4B009F2C7C /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - E51ED5A52C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5.a"; sourceTree = ""; }; - E51ED5A62C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5-ghc9.6.3.a"; sourceTree = ""; }; - E51ED5A72C7F5F4B009F2C7C /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + E5BD84482C8220D0008C24D1 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + E5BD84492C8220D0008C24D1 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + E5BD844A2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob-ghc9.6.3.a"; sourceTree = ""; }; + E5BD844B2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob.a"; sourceTree = ""; }; + E5BD844C2C8220D0008C24D1 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; E5DCF9702C590272007928CC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9722C590274007928CC /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9732C590275007928CC /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; @@ -645,14 +645,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E51ED5A82C7F5F4B009F2C7C /* libgmpxx.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, - E51ED5AC2C7F5F4B009F2C7C /* libgmp.a in Frameworks */, + E5BD844E2C8220D0008C24D1 /* libgmpxx.a in Frameworks */, + E5BD84512C8220D0008C24D1 /* libgmp.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - E51ED5AB2C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5-ghc9.6.3.a in Frameworks */, - E51ED5A92C7F5F4B009F2C7C /* libffi.a in Frameworks */, - E51ED5AA2C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, + E5BD84502C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob.a in Frameworks */, + E5BD844D2C8220D0008C24D1 /* libffi.a in Frameworks */, + E5BD844F2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob-ghc9.6.3.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -729,11 +729,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - E51ED5A42C7F5F4B009F2C7C /* libffi.a */, - E51ED5A72C7F5F4B009F2C7C /* libgmp.a */, - E51ED5A32C7F5F4B009F2C7C /* libgmpxx.a */, - E51ED5A62C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5-ghc9.6.3.a */, - E51ED5A52C7F5F4B009F2C7C /* libHSsimplex-chat-6.0.3.0-7BSMDwqB9CRFek7eb5Gzw5.a */, + E5BD84482C8220D0008C24D1 /* libffi.a */, + E5BD844C2C8220D0008C24D1 /* libgmp.a */, + E5BD84492C8220D0008C24D1 /* libgmpxx.a */, + E5BD844A2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob-ghc9.6.3.a */, + E5BD844B2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob.a */, ); path = Libraries; sourceTree = ""; @@ -2105,6 +2105,10 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Libraries", + ); "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( "$(inherited)", "$(PROJECT_DIR)/Libraries/ios", @@ -2156,6 +2160,10 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Libraries", + ); "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( "$(inherited)", "$(PROJECT_DIR)/Libraries/ios", From 4ca1b57e1b38e74fed8487c7331abe0a80c89c5c Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:34:53 +0000 Subject: [PATCH 04/19] android, desktop: small enhancements to new chat sheet (#4803) * android, desktop: small enhancements to new chat sheet * padding * normal view matching stable * fix one hand layout --------- Co-authored-by: Evgeny Poberezkin Co-authored-by: Diogo --- .../common/views/newchat/NewChatSheet.kt | 225 +++++++++--------- 1 file changed, 112 insertions(+), 113 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index 0621c5509f..99ba7be8d2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -1,7 +1,9 @@ package chat.simplex.common.views.newchat +import SectionDivider import SectionDividerSpaced import SectionItemView +import SectionSpacer import SectionView import TextIconSpaced import androidx.compose.desktop.ui.tooling.preview.Preview @@ -164,6 +166,10 @@ private fun NewChatSheetLayout( ) val sectionModifier = Modifier.fillMaxWidth() + val deletedContactTypes = listOf(ContactType.CHAT_DELETED) + val deletedChats by remember(chatModel.chats.value, deletedContactTypes) { + derivedStateOf { filterContactTypes(chatModel.chats.value, deletedContactTypes) } + } LazyColumnWithScrollBar( Modifier.fillMaxSize(), @@ -224,7 +230,9 @@ private fun NewChatSheetLayout( } } item { - Spacer(Modifier.padding(bottom = 27.dp)) + if (searchText.value.text.isEmpty()) { + Spacer(Modifier.padding(bottom = 27.dp)) + } val actionButtonsOriginal = listOf( Triple( @@ -262,37 +270,30 @@ private fun NewChatSheetLayout( } } } - - val deletedContactTypes = listOf(ContactType.CHAT_DELETED) - val deletedChats by remember(chatModel.chats.value, deletedContactTypes) { - derivedStateOf { filterContactTypes(chatModel.chats.value, deletedContactTypes) } - } if (deletedChats.isNotEmpty()) { SectionDividerSpaced(maxBottomPadding = false) - Row(modifier = sectionModifier) { - SectionView { - SectionItemView( - click = { - ModalManager.start.showCustomModal { closeDeletedChats -> - ModalView( - close = closeDeletedChats, - closeOnTop = !oneHandUI.value, - ) { - DeletedContactsView(rh = rh, closeDeletedChats = closeDeletedChats, close = { - ModalManager.start.closeModals() - }) - } + SectionView { + SectionItemView( + click = { + ModalManager.start.showCustomModal { closeDeletedChats -> + ModalView( + close = closeDeletedChats, + closeOnTop = !oneHandUI.value, + ) { + DeletedContactsView(rh = rh, closeDeletedChats = closeDeletedChats, close = { + ModalManager.start.closeModals() + }) } } - ) { - Icon( - painterResource(MR.images.ic_inventory_2), - contentDescription = stringResource(MR.strings.deleted_chats), - tint = MaterialTheme.colors.secondary, - ) - TextIconSpaced(false) - Text(text = stringResource(MR.strings.deleted_chats), color = MaterialTheme.colors.onBackground) } + ) { + Icon( + painterResource(MR.images.ic_inventory_2), + contentDescription = stringResource(MR.strings.deleted_chats), + tint = MaterialTheme.colors.secondary, + ) + TextIconSpaced(false) + Text(text = stringResource(MR.strings.deleted_chats), color = MaterialTheme.colors.onBackground) } } } @@ -300,16 +301,28 @@ private fun NewChatSheetLayout( } item { - if (filteredContactChats.isNotEmpty() && !oneHandUI.value) { - if (searchText.value.text.isNotEmpty()) { - Spacer(Modifier.height(DEFAULT_PADDING)) - } else { + if (filteredContactChats.isNotEmpty() && searchText.value.text.isEmpty()) { + if (!oneHandUI.value) { SectionDividerSpaced() + SectionView(stringResource(MR.strings.contact_list_header_title).uppercase(), headerBottomPadding = DEFAULT_PADDING_HALF) {} + } else { + SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) + SectionView(stringResource(MR.strings.contact_list_header_title).uppercase(), headerBottomPadding = DEFAULT_PADDING_HALF) {} + Spacer(Modifier.height(DEFAULT_PADDING_HALF)) + } + } + } + + item { + if (filteredContactChats.isEmpty() && allChats.isNotEmpty()) { + Column(sectionModifier.fillMaxSize().padding(DEFAULT_PADDING)) { + Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { + Text( + generalGetString(MR.strings.no_filtered_contacts), + color = MaterialTheme.colors.secondary + ) + } } - Text( - stringResource(MR.strings.contact_list_header_title).uppercase(), color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2, - modifier = sectionModifier.padding(start = DEFAULT_PADDING, bottom = DEFAULT_PADDING_HALF), fontSize = 12.sp - ) } } @@ -322,17 +335,6 @@ private fun NewChatSheetLayout( ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true) } } - - if (filteredContactChats.isEmpty() && allChats.isNotEmpty()) { - Column(sectionModifier.fillMaxSize().padding(DEFAULT_PADDING)) { - Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { - Text( - generalGetString(MR.strings.no_filtered_contacts), - color = MaterialTheme.colors.secondary - ) - } - } - } } @Composable @@ -555,78 +557,75 @@ private fun DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Un } } } - ) { - Column( - Modifier - .fillMaxSize() - .padding(it) + ) { contentPadding -> + val listState = rememberLazyListState(lazyListState.first, lazyListState.second) + val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } + val searchShowingSimplexLink = remember { mutableStateOf(false) } + val searchChatFilteredBySimplexLink = remember { mutableStateOf(null) } + val showUnreadAndFavorites = remember { appPrefs.showUnreadAndFavorites.state }.value + val allChats by remember(chatModel.chats.value) { + derivedStateOf { filterContactTypes(chatModel.chats.value, listOf(ContactType.CHAT_DELETED)) } + } + val filteredContactChats = filteredContactChats( + showUnreadAndFavorites = showUnreadAndFavorites, + searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink, + searchShowingSimplexLink = searchShowingSimplexLink, + searchText = searchText.value.text, + contactChats = allChats + ) + + LazyColumnWithScrollBar( + Modifier.fillMaxSize(), + contentPadding = contentPadding, + reverseLayout = oneHandUI.value, ) { - if (!oneHandUI.value) { - Box(contentAlignment = Alignment.Center) { - val bottomPadding = DEFAULT_PADDING - AppBarTitle( - stringResource(MR.strings.deleted_chats), - hostDevice(rh?.remoteHostId), - bottomPadding = bottomPadding - ) - } - } - - val listState = rememberLazyListState(lazyListState.first, lazyListState.second) - val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } - val searchShowingSimplexLink = remember { mutableStateOf(false) } - val searchChatFilteredBySimplexLink = remember { mutableStateOf(null) } - val showUnreadAndFavorites = remember { appPrefs.showUnreadAndFavorites.state }.value - val allChats by remember(chatModel.chats.value) { - derivedStateOf { filterContactTypes(chatModel.chats.value, listOf(ContactType.CHAT_DELETED)) } - } - val filteredContactChats = filteredContactChats( - showUnreadAndFavorites = showUnreadAndFavorites, - searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink, - searchShowingSimplexLink = searchShowingSimplexLink, - searchText = searchText.value.text, - contactChats = allChats - ) - - LazyColumnWithScrollBar( - Modifier.fillMaxSize(), - reverseLayout = oneHandUI.value, - ) { - item { - if (!oneHandUI.value) { - Divider() - } - ContactsSearchBar( - listState = listState, - searchText = searchText, - searchShowingSimplexLink = searchShowingSimplexLink, - searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink, - close = close, - ) - Divider() - - Spacer(Modifier.padding(bottom = DEFAULT_PADDING)) - } - - itemsIndexed(filteredContactChats) { index, chat -> - val nextChatSelected = remember(chat.id, filteredContactChats) { - derivedStateOf { - chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value - } - } - ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = false) - } - } - if (filteredContactChats.isEmpty() && allChats.isNotEmpty()) { - Column(Modifier.fillMaxSize().padding(DEFAULT_PADDING)) { - Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { - Text( - generalGetString(MR.strings.no_filtered_contacts), - color = MaterialTheme.colors.secondary, + item { + if (!oneHandUI.value) { + Box(contentAlignment = Alignment.Center) { + val bottomPadding = DEFAULT_PADDING + AppBarTitle( + stringResource(MR.strings.deleted_chats), + hostDevice(rh?.remoteHostId), + bottomPadding = bottomPadding ) } } } + item { + if (!oneHandUI.value) { + Divider() + } + ContactsSearchBar( + listState = listState, + searchText = searchText, + searchShowingSimplexLink = searchShowingSimplexLink, + searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink, + close = close, + ) + Divider() + } + + item { + if (filteredContactChats.isEmpty() && allChats.isNotEmpty()) { + Column(Modifier.fillMaxSize().padding(DEFAULT_PADDING)) { + Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { + Text( + generalGetString(MR.strings.no_filtered_contacts), + color = MaterialTheme.colors.secondary, + ) + } + } + } + } + + itemsIndexed(filteredContactChats) { index, chat -> + val nextChatSelected = remember(chat.id, filteredContactChats) { + derivedStateOf { + chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value + } + } + ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = false) + } } } } From 6adf8f29b087d16d2537393dbc656949f80ade11 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Fri, 30 Aug 2024 19:59:40 +0100 Subject: [PATCH 05/19] 6.0.4: ios 236, android 237, desktop 65 --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 48 +++++++++------------- apps/multiplatform/gradle.properties | 8 ++-- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index b49e8ffd11..4a537f14bf 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -1879,7 +1879,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -1904,7 +1904,7 @@ "@executable_path/Frameworks", ); LLVM_LTO = YES_THIN; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; SDKROOT = iphoneos; @@ -1928,7 +1928,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -1953,7 +1953,7 @@ "@executable_path/Frameworks", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; SDKROOT = iphoneos; @@ -1969,11 +1969,11 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -1989,11 +1989,11 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -2014,7 +2014,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GCC_OPTIMIZATION_LEVEL = s; @@ -2029,7 +2029,7 @@ "@executable_path/../../Frameworks", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2051,7 +2051,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_CODE_COVERAGE = NO; @@ -2066,7 +2066,7 @@ "@executable_path/../../Frameworks", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2088,7 +2088,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2105,10 +2105,6 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Libraries", - ); "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( "$(inherited)", "$(PROJECT_DIR)/Libraries/ios", @@ -2118,7 +2114,7 @@ "$(PROJECT_DIR)/Libraries/sim", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; @@ -2143,7 +2139,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2160,10 +2156,6 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Libraries", - ); "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( "$(inherited)", "$(PROJECT_DIR)/Libraries/ios", @@ -2173,7 +2165,7 @@ "$(PROJECT_DIR)/Libraries/sim", ); LLVM_LTO = YES; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; @@ -2198,7 +2190,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -2213,7 +2205,7 @@ "@executable_path/../../Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -2232,7 +2224,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 235; + CURRENT_PROJECT_VERSION = 236; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -2247,7 +2239,7 @@ "@executable_path/../../Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 6.0.3; + MARKETING_VERSION = 6.0.4; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; diff --git a/apps/multiplatform/gradle.properties b/apps/multiplatform/gradle.properties index c2b93f3efe..ac2fce0e12 100644 --- a/apps/multiplatform/gradle.properties +++ b/apps/multiplatform/gradle.properties @@ -26,11 +26,11 @@ android.enableJetifier=true kotlin.mpp.androidSourceSetLayoutVersion=2 kotlin.jvm.target=11 -android.version_name=6.0.3 -android.version_code=235 +android.version_name=6.0.4 +android.version_code=237 -desktop.version_name=6.0.3 -desktop.version_code=64 +desktop.version_name=6.0.4 +desktop.version_code=65 kotlin.version=1.9.23 gradle.plugin.version=8.2.0 From 41cb734d5681e6bff70a59bb100edc9e566334b1 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Fri, 30 Aug 2024 21:31:57 +0100 Subject: [PATCH 06/19] docs: FAQ on deletion of sent messages and read receipts (#4470) * docs: FAQ on deletion of sent messages and read receipts * update --- .../xcshareddata/swiftpm/Package.resolved | 3 +- docs/FAQ.md | 35 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c8623a95cb..22312bf5a1 100644 --- a/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/kirualex/SwiftyGif", "state" : { - "revision" : "5e8619335d394901379c9add5c4c1c2f420b3800" + "branch" : "master", + "revision" : "7c50eb60ca4b90043c6ad719d595803488496212" } }, { diff --git a/docs/FAQ.md b/docs/FAQ.md index a9f94b49eb..774054e58c 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -15,7 +15,9 @@ revision: 23.04.2024 - [How to configure and delete groups?](#how-to-configure-and-delete-groups) - [Are there any reactions to messages? Can I answer specific messages directly?](#are-there-any-reactions-to-messages-can-i-answer-specific-messages-directly) - [What do checkmarks mean?](#what-do-checkmarks-mean) +- [I want to see when my contacts read my messages](#i-want-to-see-when-my-contacts-read-my-messages) - [Can I use the same profile on desktop? Do messages sync cross-platform?](#can-i-use-the-same-profile-on-desktop-do-messages-sync-cross-platform) +- [Why cannot I delete messages I sent from my contact's device?](#why-cannot-i-delete-messages-i-sent-from-my-contacts-device) [Troubleshooting](#troubleshooting) - [I do not receive messages or message notifications](#i-do-not-receive-messages-or-message-notifications) @@ -79,12 +81,43 @@ It's quite simple: - two checkmarks - message is delivered to the recipient's device. "sent" means accepted by the relay for delivery, "delivered" - stored on the recipient device. -Also see [ ](#i-do-not-see-the-second-tick-on-the-messages-i-sent) +Also see: [I do not see the second tick on the messages I sent](#i-do-not-see-the-second-tick-on-the-messages-i-sent) + +### I want to see when my contacts read my messages + +To know when your contact read your messages, your contact's app has to send you a confirmation message. And vice versa, for your contact to know when you read the message, your app has to send a confirmation message. + +The important questions for this feature: +- do you always want that your contacts can see when you read all their messages? Probably, even with your close friends, sometimes you would prefer to have time before you answer their message, and also have a plausible deniability that you have not seen the message. And this should be ok - in the end, this is your device, and it should be for you to decide whether this confirmation message is sent or not, and when it is sent. +- what practical problems an automatic notification sent to your contacts when you read the message solves for you compared with you simply adding a reaction to a message or sending a quick reply? + +Overall, it seems that this feature is more damaging to your communications with your contacts than it is helpful. It keeps senders longer in the app, nervously waiting for read receipts, exploiting addicitve patterns - having you spend more time in the app is the reason why it is usually present in most messaging apps. It also creates a pressure on the recipients to reply sooner, and if read receipts are opt-in, it creates a pressure to enable it, that can be particularly damaging in any relationships with power imbalance. + +We think that delivery receipts are important and equally benefit both sides as the conversation, as they confirm that communication network functions properly. But we strongly believe that read receipts is an anti-feature that only benefits the app developers, and hurts the relations between the app users. So we are not planning to add it even as opt-in. In case you want your contact to know you've read the message put a reaction to it. And if you don't want them to know it - it is also ok, what your device sends should be under your control. ### Can I use the same profile on desktop? Do messages sync cross-platform? You can use your profile from mobile device on desktop. However, to do so you need to be on the same network, both on your mobile and desktop. More about it: [Release info](../blog/20231125-simplex-chat-v5-4-link-mobile-desktop-quantum-resistant-better-groups.md#link-mobile-and-desktop-apps-via-secure-quantum-resistant-protocol). +### Why cannot I delete messages I sent from my contact's device? + +In SimpleX Chat, you and your contacts can delete the messages you send from recipients' devices if you both agree to that within 24 hours of sending it. To be able to do that you both have to enable "Delete for everyone" option in Contact preferences - tap on the contact's name above the conversation to get there. + +You can also revoke the files you send. If the recipients did not yet receive the file, they will not be able to receive it after the file is revoked. + +This is different from most other messengers that allow deleting messages from the recipients' devices without any agreement with the recipients. + +We believe that allowing deleting information from your device to your contacts is a very wrong design decision for several reasons: +1) it violates your data sovereignty as the device owner - once your are in possession of any information, you have the rights to retain it, and any deletion should be agreed with you. And security and privacy is not possible if users don't have sovereignty over their devices. +2) it may be a business communication, and either your organisation policy or a compliance requirement is that every message you receive must be preserved for some time. +3) the message can contain a legally binding promise, effectively a contract between you and your contact, in which case you both need to keep it. +4) the messages may contain threat or abuse and you may want to keep them as a proof. +5) you may have paid for the the message (e.g., it can be a design project or consulting report), and you don't want it to suddenly disappear before you had a chance to store it outside of the conversation. + +It is also important to remember, that even if your contact enabled "Delete for everyone", you cannot really see it as a strong guarantee that the message will be deleted. Your contact's app can have a very simple modification (a one-line code change), that would prevent this deletion from happening when you request it. So you cannot see it as something that guarantees your security from your contacts. + +When "Delete for everyone" is not enabled, you can still mark the sent message as deleted within 24 hours of sending it. In this case the recipient will see it as "deleted message", and will be able to reveal the original message. + ## Troubleshooting ### I do not receive messages or message notifications From 7a5b04d523f3cede54919eb93be0df50a169bc8d Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sat, 31 Aug 2024 11:39:43 +0100 Subject: [PATCH 07/19] faq: private message routing (#4807) * faq: private message routing * readme * corrections --- README.md | 34 ++++++----- ...5.8-private-message-routing-chat-themes.md | 3 +- docs/FAQ.md | 60 +++++++++++++++++-- 3 files changed, 74 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 1a500187c0..e62fb8c8b3 100644 --- a/README.md +++ b/README.md @@ -300,25 +300,27 @@ What is already implemented: 1. Instead of user profile identifiers used by all other platforms, even the most private ones, SimpleX uses [pairwise per-queue identifiers](./docs/GLOSSARY.md#pairwise-pseudonymous-identifier) (2 addresses for each unidirectional message queue, with an optional 3rd address for push notifications on iOS, 2 queues in each connection between the users). It makes observing the network graph on the application level more difficult, as for `n` users there can be up to `n * (n-1)` message queues. 2. [End-to-end encryption](./docs/GLOSSARY.md#end-to-end-encryption) in each message queue using [NaCl cryptobox](https://nacl.cr.yp.to/box.html). This is added to allow redundancy in the future (passing each message via several servers), to avoid having the same ciphertext in different queues (that would only be visible to the attacker if TLS is compromised). The encryption keys used for this encryption are not rotated, instead we are planning to rotate the queues. Curve25519 keys are used for key negotiation. 3. [Double ratchet](./docs/GLOSSARY.md#double-ratchet-algorithm) end-to-end encryption in each conversation between two users (or group members). This is the same algorithm that is used in Signal and many other messaging apps; it provides OTR messaging with [forward secrecy](./docs/GLOSSARY.md#forward-secrecy) (each message is encrypted by its own ephemeral key) and [break-in recovery](./docs/GLOSSARY.md#post-compromise-security) (the keys are frequently re-negotiated as part of the message exchange). Two pairs of Curve448 keys are used for the initial [key agreement](./docs/GLOSSARY.md#key-agreement-protocol), initiating party passes these keys via the connection link, accepting side - in the header of the confirmation message. -4. Additional layer of encryption using NaCL cryptobox for the messages delivered from the server to the recipient. This layer avoids having any ciphertext in common between sent and received traffic of the server inside TLS (and there are no identifiers in common as well). -5. Several levels of [content padding](./docs/GLOSSARY.md#message-padding) to frustrate message size attacks. -6. All message metadata, including the time when the message was received by the server (rounded to a second) is sent to the recipients inside an encrypted envelope, so even if TLS is compromised it cannot be observed. -7. Only TLS 1.2/1.3 are allowed for client-server connections, limited to cryptographic algorithms: CHACHA20POLY1305_SHA256, Ed25519/Ed448, Curve25519/Curve448. -8. To protect against replay attacks SimpleX servers require [tlsunique channel binding](https://www.rfc-editor.org/rfc/rfc5929.html) as session ID in each client command signed with per-queue ephemeral key. -9. To protect your IP address all SimpleX Chat clients support accessing messaging servers via Tor - see [v3.1 release announcement](./blog/20220808-simplex-chat-v3.1-chat-groups.md) for more details. -10. Local database encryption with passphrase - your contacts, groups and all sent and received messages are stored encrypted. If you used SimpleX Chat before v4.0 you need to enable the encryption via the app settings. -11. Transport isolation - different TCP connections and Tor circuits are used for traffic of different user profiles, optionally - for different contacts and group member connections. -12. Manual messaging queue rotations to move conversation to another SMP relay. -13. Sending end-to-end encrypted files using [XFTP protocol](https://simplex.chat/blog/20230301-simplex-file-transfer-protocol.html). -14. Local files encryption. +4. [Post-quantum resistant key exchange](./docs/GLOSSARY.md#post-quantum-cryptography) in double ratchet protocol *on every ratchet step*. Read more in [this post](./blog/20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.md) and also see this [publication by Apple]( https://security.apple.com/blog/imessage-pq3/) explaining the need for post-quantum key rotation. +5. Additional layer of encryption using NaCL cryptobox for the messages delivered from the server to the recipient. This layer avoids having any ciphertext in common between sent and received traffic of the server inside TLS (and there are no identifiers in common as well). +6. Several levels of [content padding](./docs/GLOSSARY.md#message-padding) to frustrate message size attacks. +7. All message metadata, including the time when the message was received by the server (rounded to a second) is sent to the recipients inside an encrypted envelope, so even if TLS is compromised it cannot be observed. +8. Only TLS 1.2/1.3 are allowed for client-server connections, limited to cryptographic algorithms: CHACHA20POLY1305_SHA256, Ed25519/Ed448, Curve25519/Curve448. +9. To protect against replay attacks SimpleX servers require [tlsunique channel binding](https://www.rfc-editor.org/rfc/rfc5929.html) as session ID in each client command signed with per-queue ephemeral key. +10. To protect your IP address from unknown messaging relays, and for per-message transport anonymity (compared with Tor/VPN per-connection anonymity), from v6.0 all SimpleX Chat clients use private message routing by default. Read more in [this post](./blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md#private-message-routing). +11. To protect your IP address from unknown file relays, when SOCKS proxy is not enabled SimpleX Chat clients ask for a confirmation before downloading the files from unknown servers. +12. To protect your IP address from known servers all SimpleX Chat clients support accessing messaging servers via Tor - see [v3.1 release announcement](./blog/20220808-simplex-chat-v3.1-chat-groups.md) for more details. +13. Local database encryption with passphrase - your contacts, groups and all sent and received messages are stored encrypted. If you used SimpleX Chat before v4.0 you need to enable the encryption via the app settings. +14. Transport isolation - different TCP connections and Tor circuits are used for traffic of different user profiles, optionally - for different contacts and group member connections. +15. Manual messaging queue rotations to move conversation to another SMP relay. +16. Sending end-to-end encrypted files using [XFTP protocol](https://simplex.chat/blog/20230301-simplex-file-transfer-protocol.html). +17. Local files encryption. We plan to add: -1. Senders' SMP relays and recipients' XFTP relays to reduce traffic and conceal IP addresses from the relays chosen, and potentially controlled, by another party. -2. Post-quantum resistant key exchange in double ratchet protocol. -3. Automatic message queue rotation and redundancy. Currently the queues created between two users are used until the queue is manually changed by the user or contact is deleted. We are planning to add automatic queue rotation to make these identifiers temporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days). -4. Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time. -5. Reproducible builds – this is the limitation of the development stack, but we will be investing into solving this problem. Users can still build all applications and services from the source code. +1. Automatic message queue rotation and redundancy. Currently the queues created between two users are used until the queue is manually changed by the user or contact is deleted. We are planning to add automatic queue rotation to make these identifiers temporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days). +2. Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time. +3. Reproducible builds – this is the limitation of the development stack, but we will be investing into solving this problem. Users can still build all applications and services from the source code. +4. Recipients' XFTP relays to reduce traffic and conceal IP addresses from the relays chosen, and potentially controlled, by another party. ## For developers diff --git a/blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md b/blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md index 9e915bd3c4..0519e78e7b 100644 --- a/blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md +++ b/blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md @@ -96,8 +96,9 @@ The diagram below shows all the encryption layers used in private message routin For private routing to work, both the forwardig and the destination relays should support the updated messaging protocol - it is supported from v5.8 of the messaging relays. It is already released to all relays preset in the app, and available as a self-hosted server. We updated [the guide](../docs/SERVER.md) about how to host your own messaging relays. Because many self-hosted relays did not upgrade yet, private routing is not enabled by default. To enable it, you can open *Network & servers* settings in the app and change the settings in *Private message routing* section. We recommend setting *Private routing* option to *Unprotected* (to use it only with unknown relays and when not connecting via Tor) and *Allow downgrade* to *Yes* (so messages can still be delivered to the messaging relays that didn't upgrade yet) or to *When IP hidden* (in which case the messages will fail to deliver to unknown relays that didn't upgrade yet unless you connect to them via Tor). +See [F.A.Q. section](../docs/FAQ.md#does-simplex-protect-my-ip-address) for answers about private message routing. -Read more about the technical design of the private message routing in [this document](https://github.com/simplex-chat/simplexmq/blob/stable/rfcs/2023-09-12-second-relays.md). +Read more about the technical design of the private message routing in [this document](https://github.com/simplex-chat/simplexmq/blob/stable/rfcs/done/2023-09-12-second-relays.md) and in [the messaging protocol specification](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/simplex-messaging.md#proxying-sender-commands). ## Server transparency diff --git a/docs/FAQ.md b/docs/FAQ.md index 774054e58c..d8a8d5938f 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -32,6 +32,8 @@ revision: 23.04.2024 - [Does SimpleX support post quantum cryptography?](#does-simplex-support-post-quantum-cryptography) - [What user data can be provided on request?](#what-user-data-can-be-provided-on-request) - [Does SimpleX protect my IP address?](#does-simplex-protect-my-ip-address) +- [Doesn't private message routing reinvent Tor?](#doesnt-private-message-routing-reinvent-tor) +- [Why don't you embed Tor in SimpleX Chat app?](#why-dont-you-embed-tor-in-simplex-chat-app) - [Can I host my own relays?](#can-i-host-my-own-relays) [Funding and business model](#funding-and-business-model) @@ -91,7 +93,7 @@ The important questions for this feature: - do you always want that your contacts can see when you read all their messages? Probably, even with your close friends, sometimes you would prefer to have time before you answer their message, and also have a plausible deniability that you have not seen the message. And this should be ok - in the end, this is your device, and it should be for you to decide whether this confirmation message is sent or not, and when it is sent. - what practical problems an automatic notification sent to your contacts when you read the message solves for you compared with you simply adding a reaction to a message or sending a quick reply? -Overall, it seems that this feature is more damaging to your communications with your contacts than it is helpful. It keeps senders longer in the app, nervously waiting for read receipts, exploiting addicitve patterns - having you spend more time in the app is the reason why it is usually present in most messaging apps. It also creates a pressure on the recipients to reply sooner, and if read receipts are opt-in, it creates a pressure to enable it, that can be particularly damaging in any relationships with power imbalance. +Overall, it seems that this feature is more damaging to your communications with your contacts than it is helpful. It keeps senders longer in the app, nervously waiting for read receipts, exploiting addictive patterns - having you spend more time in the app is the reason why it is usually present in most messaging apps. It also creates a pressure on the recipients to reply sooner, and if read receipts are opt-in, it creates a pressure to enable it, that can be particularly damaging in any relationships with power imbalance. We think that delivery receipts are important and equally benefit both sides as the conversation, as they confirm that communication network functions properly. But we strongly believe that read receipts is an anti-feature that only benefits the app developers, and hurts the relations between the app users. So we are not planning to add it even as opt-in. In case you want your contact to know you've read the message put a reaction to it. And if you don't want them to know it - it is also ok, what your device sends should be under your control. @@ -109,7 +111,7 @@ This is different from most other messengers that allow deleting messages from t We believe that allowing deleting information from your device to your contacts is a very wrong design decision for several reasons: 1) it violates your data sovereignty as the device owner - once your are in possession of any information, you have the rights to retain it, and any deletion should be agreed with you. And security and privacy is not possible if users don't have sovereignty over their devices. -2) it may be a business communication, and either your organisation policy or a compliance requirement is that every message you receive must be preserved for some time. +2) it may be a business communication, and either your organization policy or a compliance requirement is that every message you receive must be preserved for some time. 3) the message can contain a legally binding promise, effectively a contract between you and your contact, in which case you both need to keep it. 4) the messages may contain threat or abuse and you may want to keep them as a proof. 5) you may have paid for the the message (e.g., it can be a design project or consulting report), and you don't want it to suddenly disappear before you had a chance to store it outside of the conversation. @@ -208,7 +210,7 @@ To determine whether it is the limitation of your, your contact's or both device - if it is shown on your screen as soon as you start the call, then your device does not support call encryption. - if in the beginning of the call your device shows "e2e encryption" but when your contact accepts the call it changes to "no e2e encryption", then it is only your contact's device that does not support it. -You need to upgrade webview (some Android systems allow it), Android system or the device to have support for e2e encryption in the calls - all modern webviews (and browsers) support it. +You need to upgrade webview (some Android systems allow it), Android system or the device to have support for e2e encryption in the calls - all modern WebViews (and browsers) support it. ### I clicked the link to connect, but could not connect @@ -232,9 +234,55 @@ Please see our [Privacy Policy](../PRIVACY.md) and [Transparency Reports](./TRAN ### Does SimpleX protect my IP address? -Not fully yet, it is a work in progress. While your device does not connect to your contacts' devices directly, as it happens in p2p networks, your contacts can self-host their relays, and you will connect to them when sending messages. A modified relay can record IP addresses connecting devices, as is the case with any other server, including Tor entry nodes, VPN providers, etc. - IP address is fundamental to Internet functioning, and there will always be some server that can observe your IP address. +Yes! -We are currently working on the next version of message routing protocol that will protect your IP address from the relays chosen by your contacts, so it will only be visible to the relays chosen by you. Read about technical details here: [RFC](https://github.com/simplex-chat/simplexmq/blob/stable/rfcs/2023-09-12-second-relays.md). +SimpleX Chat from version 6.0 uses *private message routing* whenever you send messages to unknown servers (all servers in app network settings, both enabled and not, are considered "known"). + +For private routing to work, the servers chosen by your contacts (and by the group members in your groups) must be upgraded to the recent versions. Messaging servers include support for private routing from v5.8, but we recommend using the latest versions. + +If the servers didn't upgrade, the messages would temporarily fail to deliver. You will see an orange warning icon on the message, and you can decide if you want to deliver them by connecting to these servers directly (it would require changing network settings). At the time of writing (August 2024), all preset servers and absolute majority of self-hosted servers we can see on the network support private message routing. + +With private routing enabled, instead of connecting to your contact's server directly, your client would "instruct" one of the known servers to forward the message, preventing the destination server from observing your IP address. + +Your messages are additionally end-to-end encrypted between your client and the destination server, so that the forwarding server cannot observe the destination addresses and server responses – similarly to how onion routing work. Private message routing is, effectively, a two-hop onion packet routing. + +Also, this connection is protected from man-in-the-middle attack by the forwarding server, as your client will validate destination server certificate using its fingerprint in the server address. + +You can optionally enable private message routing for all servers in Advanced network settings to complicate traffic correlation for known servers too. This will be default once the clients are improved to "know about" and to take into account network server operators. + +See [this post](../blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md#private-message-routing) for more details about how private message routing works. + +### Doesn't private message routing reinvent Tor? + +No, it does not! + +It provides better privacy for messaging than Tor, and it can be used with and without Tor or other means to additionally protect your traffic from known servers as well. + +Tor, VPN and other transport overlay networks route sockets, by creating long-lived TCP circuits between you and the destination server. While it protects your IP address, it does not protect your activity within this circuit. E.g., if you visit a website via Tor, it can still observe all pages you view within a session. Likewise, if you were connecting directly to a messaging server via Tor, this server would be able to list all message queues you send messages to. + +Private message routing routes packets (each message is one 16kb packet), not sockets. Unlike Tor and VPN, it does not create circuits between your client and destination servers. The forwarding server creates one shared session between itself and the destination, and forwards all messages from you and other clients to that destination server, mixing messages from many clients into a single TCP session. + +As each message uses its own random encryption key and random (non-sequential) identifier, the destination server cannot link multiple message queue addresses to the same client. At the same time, the forwarding server cannot observe which (and how many) addresses on the destination server your client sends messages to, thanks to e2e encryption between the client and destination server. In that regard, this design is similar to onion routing, but with per-packet anonymity, not per-circuit. + +This design is similar to mixnets (e.g. [Nym network](https://nymtech.net)), and it is tailored to the needs of message routing, providing better transport anonymity that general purpose networks, like Tor or VPN. You still can use Tor or VPN to connect to known servers, to protect your IP address from them. + +### Why don't you embed Tor in SimpleX Chat app? + +[Tor](https://www.torproject.org) is a fantastic transport overlay network - we believe it might be the best there is right now. If its [threat model](https://support.torproject.org/about/attacks-on-onion-routing/) works for you, you absolutely should use it - SimpleX Chat app supports Tor via SOCKS proxy [since v3.1](https://simplex.chat/blog/20220808-simplex-chat-v3.1-chat-groups.html#access-messaging-servers-via-tor), and SimpleX network servers can be available on both public and onion address at the same time [since v3.2](https://simplex.chat/blog/20220901-simplex-chat-v3.2-incognito-mode.html#using-onion-server-addresses-with-tor), improving anonymity of the users who use Tor. + +If you host your messaging server on the onion address only, the users who don't use Tor would still be able to message you via private message routing - all preset servers are configured to forward messages to onion-only servers. + +But there are many reasons not to embed Tor in the app: +- it increases response latency, error rate, and battery usage, and we believe that for most users enabling Tor by default would be a bad trade-off. +- it would require us regularly updating Tor library in the app, and your Tor integrity would depend on us – you would be "putting too many eggs in one basket". +- some networks restrict Tor traffic, so the app UI would have to support advanced Tor configuration, diverting our limited resources from the core app features that benefit all users. +- some countries have legislative restrictions on Tor usage, so we would have to support multiple app versions, also increasing our costs and slowing down the progress. + +The last, but not the least, it would create an unfair competitive advantage to Tor. We believe in competition, and we want our users to be able to choose which transport overlay network to use, based on what network threat model works best for them. + +If you want to use Tor or any other overlay network, such as i2p, [Nym network](https://nymtech.net), [Katzenpost](https://katzenpost.network), etc., you need to research their limitations, because none of them provides absolute anonymity against all possible attackers. + +And if after that research you decide to use Tor, it takes about 2 minutes to install and start [Orbot app](https://guardianproject.info/apps/org.torproject.android/). We believe that if it seems complex, then you *should not* be using Tor - it is an advanced technology that can only improve your privacy and anonymity if you understand its limitations and know how to configure it. ### Can I host my own relays? @@ -244,7 +292,7 @@ Of course! Please check these tutorials: [SMP server](./SERVER.md) and [XFTP ser ### How are you funded? -SimpleX Chat Ltd is funded by private investors and venture capital. As an open-source project, it is also being generously supported by donations as well. Read [more details](../blog/20230422-simplex-chat-vision-funding-v5-videos-files-passcode.md#how-is-it-funded-and-what-is-the-business-model). +SimpleX Chat Ltd is funded by private investors and venture capital. As an open-source project, it is also being generously supported by donations as well. Read the posts [from 2023](../blog/20230422-simplex-chat-vision-funding-v5-videos-files-passcode.md#how-is-it-funded-and-what-is-the-business-model) and [from 2024](../blog/20240814-simplex-chat-vision-funding-v6-private-routing-new-user-experience.md) for more details. ### Why VCs? From 8cc03b6c21dd407248ad2517281e7d2a51e988f2 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Fri, 30 Aug 2024 21:31:57 +0100 Subject: [PATCH 08/19] docs: FAQ on deletion of sent messages and read receipts (#4470) * docs: FAQ on deletion of sent messages and read receipts * update --- .../xcshareddata/swiftpm/Package.resolved | 3 +- docs/FAQ.md | 35 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c8623a95cb..22312bf5a1 100644 --- a/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/kirualex/SwiftyGif", "state" : { - "revision" : "5e8619335d394901379c9add5c4c1c2f420b3800" + "branch" : "master", + "revision" : "7c50eb60ca4b90043c6ad719d595803488496212" } }, { diff --git a/docs/FAQ.md b/docs/FAQ.md index a9f94b49eb..774054e58c 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -15,7 +15,9 @@ revision: 23.04.2024 - [How to configure and delete groups?](#how-to-configure-and-delete-groups) - [Are there any reactions to messages? Can I answer specific messages directly?](#are-there-any-reactions-to-messages-can-i-answer-specific-messages-directly) - [What do checkmarks mean?](#what-do-checkmarks-mean) +- [I want to see when my contacts read my messages](#i-want-to-see-when-my-contacts-read-my-messages) - [Can I use the same profile on desktop? Do messages sync cross-platform?](#can-i-use-the-same-profile-on-desktop-do-messages-sync-cross-platform) +- [Why cannot I delete messages I sent from my contact's device?](#why-cannot-i-delete-messages-i-sent-from-my-contacts-device) [Troubleshooting](#troubleshooting) - [I do not receive messages or message notifications](#i-do-not-receive-messages-or-message-notifications) @@ -79,12 +81,43 @@ It's quite simple: - two checkmarks - message is delivered to the recipient's device. "sent" means accepted by the relay for delivery, "delivered" - stored on the recipient device. -Also see [ ](#i-do-not-see-the-second-tick-on-the-messages-i-sent) +Also see: [I do not see the second tick on the messages I sent](#i-do-not-see-the-second-tick-on-the-messages-i-sent) + +### I want to see when my contacts read my messages + +To know when your contact read your messages, your contact's app has to send you a confirmation message. And vice versa, for your contact to know when you read the message, your app has to send a confirmation message. + +The important questions for this feature: +- do you always want that your contacts can see when you read all their messages? Probably, even with your close friends, sometimes you would prefer to have time before you answer their message, and also have a plausible deniability that you have not seen the message. And this should be ok - in the end, this is your device, and it should be for you to decide whether this confirmation message is sent or not, and when it is sent. +- what practical problems an automatic notification sent to your contacts when you read the message solves for you compared with you simply adding a reaction to a message or sending a quick reply? + +Overall, it seems that this feature is more damaging to your communications with your contacts than it is helpful. It keeps senders longer in the app, nervously waiting for read receipts, exploiting addicitve patterns - having you spend more time in the app is the reason why it is usually present in most messaging apps. It also creates a pressure on the recipients to reply sooner, and if read receipts are opt-in, it creates a pressure to enable it, that can be particularly damaging in any relationships with power imbalance. + +We think that delivery receipts are important and equally benefit both sides as the conversation, as they confirm that communication network functions properly. But we strongly believe that read receipts is an anti-feature that only benefits the app developers, and hurts the relations between the app users. So we are not planning to add it even as opt-in. In case you want your contact to know you've read the message put a reaction to it. And if you don't want them to know it - it is also ok, what your device sends should be under your control. ### Can I use the same profile on desktop? Do messages sync cross-platform? You can use your profile from mobile device on desktop. However, to do so you need to be on the same network, both on your mobile and desktop. More about it: [Release info](../blog/20231125-simplex-chat-v5-4-link-mobile-desktop-quantum-resistant-better-groups.md#link-mobile-and-desktop-apps-via-secure-quantum-resistant-protocol). +### Why cannot I delete messages I sent from my contact's device? + +In SimpleX Chat, you and your contacts can delete the messages you send from recipients' devices if you both agree to that within 24 hours of sending it. To be able to do that you both have to enable "Delete for everyone" option in Contact preferences - tap on the contact's name above the conversation to get there. + +You can also revoke the files you send. If the recipients did not yet receive the file, they will not be able to receive it after the file is revoked. + +This is different from most other messengers that allow deleting messages from the recipients' devices without any agreement with the recipients. + +We believe that allowing deleting information from your device to your contacts is a very wrong design decision for several reasons: +1) it violates your data sovereignty as the device owner - once your are in possession of any information, you have the rights to retain it, and any deletion should be agreed with you. And security and privacy is not possible if users don't have sovereignty over their devices. +2) it may be a business communication, and either your organisation policy or a compliance requirement is that every message you receive must be preserved for some time. +3) the message can contain a legally binding promise, effectively a contract between you and your contact, in which case you both need to keep it. +4) the messages may contain threat or abuse and you may want to keep them as a proof. +5) you may have paid for the the message (e.g., it can be a design project or consulting report), and you don't want it to suddenly disappear before you had a chance to store it outside of the conversation. + +It is also important to remember, that even if your contact enabled "Delete for everyone", you cannot really see it as a strong guarantee that the message will be deleted. Your contact's app can have a very simple modification (a one-line code change), that would prevent this deletion from happening when you request it. So you cannot see it as something that guarantees your security from your contacts. + +When "Delete for everyone" is not enabled, you can still mark the sent message as deleted within 24 hours of sending it. In this case the recipient will see it as "deleted message", and will be able to reveal the original message. + ## Troubleshooting ### I do not receive messages or message notifications From fff29f8548241461247f762307005114a64b6ccb Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sat, 31 Aug 2024 11:39:43 +0100 Subject: [PATCH 09/19] faq: private message routing (#4807) * faq: private message routing * readme * corrections --- README.md | 34 ++++++----- ...5.8-private-message-routing-chat-themes.md | 3 +- docs/FAQ.md | 60 +++++++++++++++++-- 3 files changed, 74 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 1a500187c0..e62fb8c8b3 100644 --- a/README.md +++ b/README.md @@ -300,25 +300,27 @@ What is already implemented: 1. Instead of user profile identifiers used by all other platforms, even the most private ones, SimpleX uses [pairwise per-queue identifiers](./docs/GLOSSARY.md#pairwise-pseudonymous-identifier) (2 addresses for each unidirectional message queue, with an optional 3rd address for push notifications on iOS, 2 queues in each connection between the users). It makes observing the network graph on the application level more difficult, as for `n` users there can be up to `n * (n-1)` message queues. 2. [End-to-end encryption](./docs/GLOSSARY.md#end-to-end-encryption) in each message queue using [NaCl cryptobox](https://nacl.cr.yp.to/box.html). This is added to allow redundancy in the future (passing each message via several servers), to avoid having the same ciphertext in different queues (that would only be visible to the attacker if TLS is compromised). The encryption keys used for this encryption are not rotated, instead we are planning to rotate the queues. Curve25519 keys are used for key negotiation. 3. [Double ratchet](./docs/GLOSSARY.md#double-ratchet-algorithm) end-to-end encryption in each conversation between two users (or group members). This is the same algorithm that is used in Signal and many other messaging apps; it provides OTR messaging with [forward secrecy](./docs/GLOSSARY.md#forward-secrecy) (each message is encrypted by its own ephemeral key) and [break-in recovery](./docs/GLOSSARY.md#post-compromise-security) (the keys are frequently re-negotiated as part of the message exchange). Two pairs of Curve448 keys are used for the initial [key agreement](./docs/GLOSSARY.md#key-agreement-protocol), initiating party passes these keys via the connection link, accepting side - in the header of the confirmation message. -4. Additional layer of encryption using NaCL cryptobox for the messages delivered from the server to the recipient. This layer avoids having any ciphertext in common between sent and received traffic of the server inside TLS (and there are no identifiers in common as well). -5. Several levels of [content padding](./docs/GLOSSARY.md#message-padding) to frustrate message size attacks. -6. All message metadata, including the time when the message was received by the server (rounded to a second) is sent to the recipients inside an encrypted envelope, so even if TLS is compromised it cannot be observed. -7. Only TLS 1.2/1.3 are allowed for client-server connections, limited to cryptographic algorithms: CHACHA20POLY1305_SHA256, Ed25519/Ed448, Curve25519/Curve448. -8. To protect against replay attacks SimpleX servers require [tlsunique channel binding](https://www.rfc-editor.org/rfc/rfc5929.html) as session ID in each client command signed with per-queue ephemeral key. -9. To protect your IP address all SimpleX Chat clients support accessing messaging servers via Tor - see [v3.1 release announcement](./blog/20220808-simplex-chat-v3.1-chat-groups.md) for more details. -10. Local database encryption with passphrase - your contacts, groups and all sent and received messages are stored encrypted. If you used SimpleX Chat before v4.0 you need to enable the encryption via the app settings. -11. Transport isolation - different TCP connections and Tor circuits are used for traffic of different user profiles, optionally - for different contacts and group member connections. -12. Manual messaging queue rotations to move conversation to another SMP relay. -13. Sending end-to-end encrypted files using [XFTP protocol](https://simplex.chat/blog/20230301-simplex-file-transfer-protocol.html). -14. Local files encryption. +4. [Post-quantum resistant key exchange](./docs/GLOSSARY.md#post-quantum-cryptography) in double ratchet protocol *on every ratchet step*. Read more in [this post](./blog/20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.md) and also see this [publication by Apple]( https://security.apple.com/blog/imessage-pq3/) explaining the need for post-quantum key rotation. +5. Additional layer of encryption using NaCL cryptobox for the messages delivered from the server to the recipient. This layer avoids having any ciphertext in common between sent and received traffic of the server inside TLS (and there are no identifiers in common as well). +6. Several levels of [content padding](./docs/GLOSSARY.md#message-padding) to frustrate message size attacks. +7. All message metadata, including the time when the message was received by the server (rounded to a second) is sent to the recipients inside an encrypted envelope, so even if TLS is compromised it cannot be observed. +8. Only TLS 1.2/1.3 are allowed for client-server connections, limited to cryptographic algorithms: CHACHA20POLY1305_SHA256, Ed25519/Ed448, Curve25519/Curve448. +9. To protect against replay attacks SimpleX servers require [tlsunique channel binding](https://www.rfc-editor.org/rfc/rfc5929.html) as session ID in each client command signed with per-queue ephemeral key. +10. To protect your IP address from unknown messaging relays, and for per-message transport anonymity (compared with Tor/VPN per-connection anonymity), from v6.0 all SimpleX Chat clients use private message routing by default. Read more in [this post](./blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md#private-message-routing). +11. To protect your IP address from unknown file relays, when SOCKS proxy is not enabled SimpleX Chat clients ask for a confirmation before downloading the files from unknown servers. +12. To protect your IP address from known servers all SimpleX Chat clients support accessing messaging servers via Tor - see [v3.1 release announcement](./blog/20220808-simplex-chat-v3.1-chat-groups.md) for more details. +13. Local database encryption with passphrase - your contacts, groups and all sent and received messages are stored encrypted. If you used SimpleX Chat before v4.0 you need to enable the encryption via the app settings. +14. Transport isolation - different TCP connections and Tor circuits are used for traffic of different user profiles, optionally - for different contacts and group member connections. +15. Manual messaging queue rotations to move conversation to another SMP relay. +16. Sending end-to-end encrypted files using [XFTP protocol](https://simplex.chat/blog/20230301-simplex-file-transfer-protocol.html). +17. Local files encryption. We plan to add: -1. Senders' SMP relays and recipients' XFTP relays to reduce traffic and conceal IP addresses from the relays chosen, and potentially controlled, by another party. -2. Post-quantum resistant key exchange in double ratchet protocol. -3. Automatic message queue rotation and redundancy. Currently the queues created between two users are used until the queue is manually changed by the user or contact is deleted. We are planning to add automatic queue rotation to make these identifiers temporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days). -4. Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time. -5. Reproducible builds – this is the limitation of the development stack, but we will be investing into solving this problem. Users can still build all applications and services from the source code. +1. Automatic message queue rotation and redundancy. Currently the queues created between two users are used until the queue is manually changed by the user or contact is deleted. We are planning to add automatic queue rotation to make these identifiers temporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days). +2. Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time. +3. Reproducible builds – this is the limitation of the development stack, but we will be investing into solving this problem. Users can still build all applications and services from the source code. +4. Recipients' XFTP relays to reduce traffic and conceal IP addresses from the relays chosen, and potentially controlled, by another party. ## For developers diff --git a/blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md b/blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md index 9e915bd3c4..0519e78e7b 100644 --- a/blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md +++ b/blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md @@ -96,8 +96,9 @@ The diagram below shows all the encryption layers used in private message routin For private routing to work, both the forwardig and the destination relays should support the updated messaging protocol - it is supported from v5.8 of the messaging relays. It is already released to all relays preset in the app, and available as a self-hosted server. We updated [the guide](../docs/SERVER.md) about how to host your own messaging relays. Because many self-hosted relays did not upgrade yet, private routing is not enabled by default. To enable it, you can open *Network & servers* settings in the app and change the settings in *Private message routing* section. We recommend setting *Private routing* option to *Unprotected* (to use it only with unknown relays and when not connecting via Tor) and *Allow downgrade* to *Yes* (so messages can still be delivered to the messaging relays that didn't upgrade yet) or to *When IP hidden* (in which case the messages will fail to deliver to unknown relays that didn't upgrade yet unless you connect to them via Tor). +See [F.A.Q. section](../docs/FAQ.md#does-simplex-protect-my-ip-address) for answers about private message routing. -Read more about the technical design of the private message routing in [this document](https://github.com/simplex-chat/simplexmq/blob/stable/rfcs/2023-09-12-second-relays.md). +Read more about the technical design of the private message routing in [this document](https://github.com/simplex-chat/simplexmq/blob/stable/rfcs/done/2023-09-12-second-relays.md) and in [the messaging protocol specification](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/simplex-messaging.md#proxying-sender-commands). ## Server transparency diff --git a/docs/FAQ.md b/docs/FAQ.md index 774054e58c..d8a8d5938f 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -32,6 +32,8 @@ revision: 23.04.2024 - [Does SimpleX support post quantum cryptography?](#does-simplex-support-post-quantum-cryptography) - [What user data can be provided on request?](#what-user-data-can-be-provided-on-request) - [Does SimpleX protect my IP address?](#does-simplex-protect-my-ip-address) +- [Doesn't private message routing reinvent Tor?](#doesnt-private-message-routing-reinvent-tor) +- [Why don't you embed Tor in SimpleX Chat app?](#why-dont-you-embed-tor-in-simplex-chat-app) - [Can I host my own relays?](#can-i-host-my-own-relays) [Funding and business model](#funding-and-business-model) @@ -91,7 +93,7 @@ The important questions for this feature: - do you always want that your contacts can see when you read all their messages? Probably, even with your close friends, sometimes you would prefer to have time before you answer their message, and also have a plausible deniability that you have not seen the message. And this should be ok - in the end, this is your device, and it should be for you to decide whether this confirmation message is sent or not, and when it is sent. - what practical problems an automatic notification sent to your contacts when you read the message solves for you compared with you simply adding a reaction to a message or sending a quick reply? -Overall, it seems that this feature is more damaging to your communications with your contacts than it is helpful. It keeps senders longer in the app, nervously waiting for read receipts, exploiting addicitve patterns - having you spend more time in the app is the reason why it is usually present in most messaging apps. It also creates a pressure on the recipients to reply sooner, and if read receipts are opt-in, it creates a pressure to enable it, that can be particularly damaging in any relationships with power imbalance. +Overall, it seems that this feature is more damaging to your communications with your contacts than it is helpful. It keeps senders longer in the app, nervously waiting for read receipts, exploiting addictive patterns - having you spend more time in the app is the reason why it is usually present in most messaging apps. It also creates a pressure on the recipients to reply sooner, and if read receipts are opt-in, it creates a pressure to enable it, that can be particularly damaging in any relationships with power imbalance. We think that delivery receipts are important and equally benefit both sides as the conversation, as they confirm that communication network functions properly. But we strongly believe that read receipts is an anti-feature that only benefits the app developers, and hurts the relations between the app users. So we are not planning to add it even as opt-in. In case you want your contact to know you've read the message put a reaction to it. And if you don't want them to know it - it is also ok, what your device sends should be under your control. @@ -109,7 +111,7 @@ This is different from most other messengers that allow deleting messages from t We believe that allowing deleting information from your device to your contacts is a very wrong design decision for several reasons: 1) it violates your data sovereignty as the device owner - once your are in possession of any information, you have the rights to retain it, and any deletion should be agreed with you. And security and privacy is not possible if users don't have sovereignty over their devices. -2) it may be a business communication, and either your organisation policy or a compliance requirement is that every message you receive must be preserved for some time. +2) it may be a business communication, and either your organization policy or a compliance requirement is that every message you receive must be preserved for some time. 3) the message can contain a legally binding promise, effectively a contract between you and your contact, in which case you both need to keep it. 4) the messages may contain threat or abuse and you may want to keep them as a proof. 5) you may have paid for the the message (e.g., it can be a design project or consulting report), and you don't want it to suddenly disappear before you had a chance to store it outside of the conversation. @@ -208,7 +210,7 @@ To determine whether it is the limitation of your, your contact's or both device - if it is shown on your screen as soon as you start the call, then your device does not support call encryption. - if in the beginning of the call your device shows "e2e encryption" but when your contact accepts the call it changes to "no e2e encryption", then it is only your contact's device that does not support it. -You need to upgrade webview (some Android systems allow it), Android system or the device to have support for e2e encryption in the calls - all modern webviews (and browsers) support it. +You need to upgrade webview (some Android systems allow it), Android system or the device to have support for e2e encryption in the calls - all modern WebViews (and browsers) support it. ### I clicked the link to connect, but could not connect @@ -232,9 +234,55 @@ Please see our [Privacy Policy](../PRIVACY.md) and [Transparency Reports](./TRAN ### Does SimpleX protect my IP address? -Not fully yet, it is a work in progress. While your device does not connect to your contacts' devices directly, as it happens in p2p networks, your contacts can self-host their relays, and you will connect to them when sending messages. A modified relay can record IP addresses connecting devices, as is the case with any other server, including Tor entry nodes, VPN providers, etc. - IP address is fundamental to Internet functioning, and there will always be some server that can observe your IP address. +Yes! -We are currently working on the next version of message routing protocol that will protect your IP address from the relays chosen by your contacts, so it will only be visible to the relays chosen by you. Read about technical details here: [RFC](https://github.com/simplex-chat/simplexmq/blob/stable/rfcs/2023-09-12-second-relays.md). +SimpleX Chat from version 6.0 uses *private message routing* whenever you send messages to unknown servers (all servers in app network settings, both enabled and not, are considered "known"). + +For private routing to work, the servers chosen by your contacts (and by the group members in your groups) must be upgraded to the recent versions. Messaging servers include support for private routing from v5.8, but we recommend using the latest versions. + +If the servers didn't upgrade, the messages would temporarily fail to deliver. You will see an orange warning icon on the message, and you can decide if you want to deliver them by connecting to these servers directly (it would require changing network settings). At the time of writing (August 2024), all preset servers and absolute majority of self-hosted servers we can see on the network support private message routing. + +With private routing enabled, instead of connecting to your contact's server directly, your client would "instruct" one of the known servers to forward the message, preventing the destination server from observing your IP address. + +Your messages are additionally end-to-end encrypted between your client and the destination server, so that the forwarding server cannot observe the destination addresses and server responses – similarly to how onion routing work. Private message routing is, effectively, a two-hop onion packet routing. + +Also, this connection is protected from man-in-the-middle attack by the forwarding server, as your client will validate destination server certificate using its fingerprint in the server address. + +You can optionally enable private message routing for all servers in Advanced network settings to complicate traffic correlation for known servers too. This will be default once the clients are improved to "know about" and to take into account network server operators. + +See [this post](../blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md#private-message-routing) for more details about how private message routing works. + +### Doesn't private message routing reinvent Tor? + +No, it does not! + +It provides better privacy for messaging than Tor, and it can be used with and without Tor or other means to additionally protect your traffic from known servers as well. + +Tor, VPN and other transport overlay networks route sockets, by creating long-lived TCP circuits between you and the destination server. While it protects your IP address, it does not protect your activity within this circuit. E.g., if you visit a website via Tor, it can still observe all pages you view within a session. Likewise, if you were connecting directly to a messaging server via Tor, this server would be able to list all message queues you send messages to. + +Private message routing routes packets (each message is one 16kb packet), not sockets. Unlike Tor and VPN, it does not create circuits between your client and destination servers. The forwarding server creates one shared session between itself and the destination, and forwards all messages from you and other clients to that destination server, mixing messages from many clients into a single TCP session. + +As each message uses its own random encryption key and random (non-sequential) identifier, the destination server cannot link multiple message queue addresses to the same client. At the same time, the forwarding server cannot observe which (and how many) addresses on the destination server your client sends messages to, thanks to e2e encryption between the client and destination server. In that regard, this design is similar to onion routing, but with per-packet anonymity, not per-circuit. + +This design is similar to mixnets (e.g. [Nym network](https://nymtech.net)), and it is tailored to the needs of message routing, providing better transport anonymity that general purpose networks, like Tor or VPN. You still can use Tor or VPN to connect to known servers, to protect your IP address from them. + +### Why don't you embed Tor in SimpleX Chat app? + +[Tor](https://www.torproject.org) is a fantastic transport overlay network - we believe it might be the best there is right now. If its [threat model](https://support.torproject.org/about/attacks-on-onion-routing/) works for you, you absolutely should use it - SimpleX Chat app supports Tor via SOCKS proxy [since v3.1](https://simplex.chat/blog/20220808-simplex-chat-v3.1-chat-groups.html#access-messaging-servers-via-tor), and SimpleX network servers can be available on both public and onion address at the same time [since v3.2](https://simplex.chat/blog/20220901-simplex-chat-v3.2-incognito-mode.html#using-onion-server-addresses-with-tor), improving anonymity of the users who use Tor. + +If you host your messaging server on the onion address only, the users who don't use Tor would still be able to message you via private message routing - all preset servers are configured to forward messages to onion-only servers. + +But there are many reasons not to embed Tor in the app: +- it increases response latency, error rate, and battery usage, and we believe that for most users enabling Tor by default would be a bad trade-off. +- it would require us regularly updating Tor library in the app, and your Tor integrity would depend on us – you would be "putting too many eggs in one basket". +- some networks restrict Tor traffic, so the app UI would have to support advanced Tor configuration, diverting our limited resources from the core app features that benefit all users. +- some countries have legislative restrictions on Tor usage, so we would have to support multiple app versions, also increasing our costs and slowing down the progress. + +The last, but not the least, it would create an unfair competitive advantage to Tor. We believe in competition, and we want our users to be able to choose which transport overlay network to use, based on what network threat model works best for them. + +If you want to use Tor or any other overlay network, such as i2p, [Nym network](https://nymtech.net), [Katzenpost](https://katzenpost.network), etc., you need to research their limitations, because none of them provides absolute anonymity against all possible attackers. + +And if after that research you decide to use Tor, it takes about 2 minutes to install and start [Orbot app](https://guardianproject.info/apps/org.torproject.android/). We believe that if it seems complex, then you *should not* be using Tor - it is an advanced technology that can only improve your privacy and anonymity if you understand its limitations and know how to configure it. ### Can I host my own relays? @@ -244,7 +292,7 @@ Of course! Please check these tutorials: [SMP server](./SERVER.md) and [XFTP ser ### How are you funded? -SimpleX Chat Ltd is funded by private investors and venture capital. As an open-source project, it is also being generously supported by donations as well. Read [more details](../blog/20230422-simplex-chat-vision-funding-v5-videos-files-passcode.md#how-is-it-funded-and-what-is-the-business-model). +SimpleX Chat Ltd is funded by private investors and venture capital. As an open-source project, it is also being generously supported by donations as well. Read the posts [from 2023](../blog/20230422-simplex-chat-vision-funding-v5-videos-files-passcode.md#how-is-it-funded-and-what-is-the-business-model) and [from 2024](../blog/20240814-simplex-chat-vision-funding-v6-private-routing-new-user-experience.md) for more details. ### Why VCs? From d68a3ba80d356815c53d1910be434c3d5f3a995c Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Sat, 31 Aug 2024 11:58:49 +0100 Subject: [PATCH 10/19] ios: update core library --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 43 +++++++++---------- .../xcshareddata/swiftpm/Package.resolved | 3 +- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 03c1108cd0..3700fbbf16 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -214,11 +214,11 @@ D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; }; D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; }; E51CC1E62C62085600DB91FE /* OneHandUICard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51CC1E52C62085600DB91FE /* OneHandUICard.swift */; }; - E51ED5942C7B9983009F2C7C /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED58F2C7B9983009F2C7C /* libgmpxx.a */; }; - E51ED5952C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5902C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx-ghc9.6.3.a */; }; - E51ED5962C7B9983009F2C7C /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5912C7B9983009F2C7C /* libgmp.a */; }; - E51ED5972C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5922C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx.a */; }; - E51ED5982C7B9983009F2C7C /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51ED5932C7B9983009F2C7C /* libffi.a */; }; + E5BD84572C832BF9008C24D1 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD84522C832BF9008C24D1 /* libgmpxx.a */; }; + E5BD84582C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD84532C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N.a */; }; + E5BD84592C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD84542C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N-ghc9.6.3.a */; }; + E5BD845A2C832BF9008C24D1 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD84552C832BF9008C24D1 /* libgmp.a */; }; + E5BD845B2C832BF9008C24D1 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5BD84562C832BF9008C24D1 /* libffi.a */; }; E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; }; E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; }; E5DCF9842C5902CE007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF9822C5902CE007928CC /* Localizable.strings */; }; @@ -550,11 +550,11 @@ D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; }; D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; E51CC1E52C62085600DB91FE /* OneHandUICard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneHandUICard.swift; sourceTree = ""; }; - E51ED58F2C7B9983009F2C7C /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - E51ED5902C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx-ghc9.6.3.a"; sourceTree = ""; }; - E51ED5912C7B9983009F2C7C /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - E51ED5922C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx.a"; sourceTree = ""; }; - E51ED5932C7B9983009F2C7C /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + E5BD84522C832BF9008C24D1 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + E5BD84532C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N.a"; sourceTree = ""; }; + E5BD84542C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N-ghc9.6.3.a"; sourceTree = ""; }; + E5BD84552C832BF9008C24D1 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + E5BD84562C832BF9008C24D1 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; E5DCF9702C590272007928CC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9722C590274007928CC /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9732C590275007928CC /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; @@ -645,17 +645,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E51ED5942C7B9983009F2C7C /* libgmpxx.a in Frameworks */, + E5BD84572C832BF9008C24D1 /* libgmpxx.a in Frameworks */, + E5BD845A2C832BF9008C24D1 /* libgmp.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, + E5BD845B2C832BF9008C24D1 /* libffi.a in Frameworks */, + E5BD84582C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N.a in Frameworks */, + E5BD84592C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N-ghc9.6.3.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - E51ED5982C7B9983009F2C7C /* libffi.a in Frameworks */, - E51ED5972C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx.a in Frameworks */, - E51ED5952C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx-ghc9.6.3.a in Frameworks */, - E51ED5962C7B9983009F2C7C /* libgmp.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, - E5BD84502C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob.a in Frameworks */, - E5BD844D2C8220D0008C24D1 /* libffi.a in Frameworks */, - E5BD844F2C8220D0008C24D1 /* libHSsimplex-chat-6.0.4.0-2x1D8vVukGZOGJwEVzeob-ghc9.6.3.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -732,11 +729,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - E51ED5932C7B9983009F2C7C /* libffi.a */, - E51ED5912C7B9983009F2C7C /* libgmp.a */, - E51ED58F2C7B9983009F2C7C /* libgmpxx.a */, - E51ED5902C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx-ghc9.6.3.a */, - E51ED5922C7B9983009F2C7C /* libHSsimplex-chat-6.1.0.0-2HbUlAtNXgRGMjFy4vK7lx.a */, + E5BD84562C832BF9008C24D1 /* libffi.a */, + E5BD84552C832BF9008C24D1 /* libgmp.a */, + E5BD84522C832BF9008C24D1 /* libgmpxx.a */, + E5BD84542C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N-ghc9.6.3.a */, + E5BD84532C832BF9008C24D1 /* libHSsimplex-chat-6.1.0.0-1tXK6wuT4H71iMwoWdPa4N.a */, ); path = Libraries; sourceTree = ""; diff --git a/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 22312bf5a1..c8623a95cb 100644 --- a/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,8 +23,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/kirualex/SwiftyGif", "state" : { - "branch" : "master", - "revision" : "7c50eb60ca4b90043c6ad719d595803488496212" + "revision" : "5e8619335d394901379c9add5c4c1c2f420b3800" } }, { From f94f0dea082bea18a8c4152a38066e47c731bb81 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Sat, 31 Aug 2024 14:34:46 +0100 Subject: [PATCH 11/19] website: fix links --- docs/TRANSPARENCY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/TRANSPARENCY.md b/docs/TRANSPARENCY.md index 43fdd12ac5..bae7a4f781 100644 --- a/docs/TRANSPARENCY.md +++ b/docs/TRANSPARENCY.md @@ -17,8 +17,8 @@ This page will include any and all reports on requests for user data. Our objective is to consistently ensure that no user data and absolute minimum of the metadata required for the network to function is available for disclosure by any infrastructure operators, under any circumstances. **Helpful resources**: -- [Privacy policy](../PRIVACY.md) -- [Privacy and security: technical details and limitations](../README.md#privacy-and-security-technical-details-and-limitations) +- [Privacy policy](/PRIVACY.md) +- [Privacy and security: technical details and limitations](https://github.com/simplex-chat/simplex-chat/blob/stable/README.md#privacy-and-security-technical-details-and-limitations) - Whitepaper: - [Trust in servers](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md#trust-in-servers) - [Encryption Primitives Used](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md#encryption-primitives-used) From 3b49817f173a0de33638c4f6ed703545420f9f0a Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Sat, 31 Aug 2024 17:24:50 +0000 Subject: [PATCH 12/19] desktop: fix vlc dependency (#4809) --- apps/multiplatform/common/build.gradle.kts | 2 +- apps/multiplatform/desktop/build.gradle.kts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/multiplatform/common/build.gradle.kts b/apps/multiplatform/common/build.gradle.kts index a1afb655e2..1670672753 100644 --- a/apps/multiplatform/common/build.gradle.kts +++ b/apps/multiplatform/common/build.gradle.kts @@ -102,7 +102,7 @@ kotlin { implementation("com.github.Dansoftowner:jSystemThemeDetector:3.8") implementation("com.sshtools:two-slices:0.9.0-SNAPSHOT") implementation("org.slf4j:slf4j-simple:2.0.12") - implementation("uk.co.caprica:vlcj:4.8.2") + implementation("uk.co.caprica:vlcj:4.8.3") implementation("com.github.NanoHttpd.nanohttpd:nanohttpd:efb2ebf85a") implementation("com.github.NanoHttpd.nanohttpd:nanohttpd-websocket:efb2ebf85a") implementation("com.squareup.okhttp3:okhttp:4.12.0") diff --git a/apps/multiplatform/desktop/build.gradle.kts b/apps/multiplatform/desktop/build.gradle.kts index 401c2938d5..e39ba48a0b 100644 --- a/apps/multiplatform/desktop/build.gradle.kts +++ b/apps/multiplatform/desktop/build.gradle.kts @@ -18,7 +18,6 @@ kotlin { dependencies { implementation(project(":common")) implementation(compose.desktop.currentOs) - implementation("net.java.dev.jna:jna:5.14.0") } } val jvmTest by getting From 087519c39def7da152fb976f2aeb362bd8906a8a Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Sat, 31 Aug 2024 17:24:50 +0000 Subject: [PATCH 13/19] desktop: fix vlc dependency (#4809) --- apps/multiplatform/common/build.gradle.kts | 2 +- apps/multiplatform/desktop/build.gradle.kts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/multiplatform/common/build.gradle.kts b/apps/multiplatform/common/build.gradle.kts index 7e97ea3414..dd9c7ab161 100644 --- a/apps/multiplatform/common/build.gradle.kts +++ b/apps/multiplatform/common/build.gradle.kts @@ -102,7 +102,7 @@ kotlin { implementation("com.github.Dansoftowner:jSystemThemeDetector:3.8") implementation("com.sshtools:two-slices:0.9.0-SNAPSHOT") implementation("org.slf4j:slf4j-simple:2.0.12") - implementation("uk.co.caprica:vlcj:4.8.2") + implementation("uk.co.caprica:vlcj:4.8.3") implementation("com.github.NanoHttpd.nanohttpd:nanohttpd:efb2ebf85a") implementation("com.github.NanoHttpd.nanohttpd:nanohttpd-websocket:efb2ebf85a") implementation("com.squareup.okhttp3:okhttp:4.12.0") diff --git a/apps/multiplatform/desktop/build.gradle.kts b/apps/multiplatform/desktop/build.gradle.kts index 401c2938d5..e39ba48a0b 100644 --- a/apps/multiplatform/desktop/build.gradle.kts +++ b/apps/multiplatform/desktop/build.gradle.kts @@ -18,7 +18,6 @@ kotlin { dependencies { implementation(project(":common")) implementation(compose.desktop.currentOs) - implementation("net.java.dev.jna:jna:5.14.0") } } val jvmTest by getting From fe20a43232cb083c3b5930afbfad3f6f0d70432b Mon Sep 17 00:00:00 2001 From: sh <37271604+shumvgolove@users.noreply.github.com> Date: Mon, 2 Sep 2024 18:15:16 +0400 Subject: [PATCH 14/19] flatpak: update metainfo (#4811) --- .../flatpak/chat.simplex.simplex.metainfo.xml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/scripts/flatpak/chat.simplex.simplex.metainfo.xml b/scripts/flatpak/chat.simplex.simplex.metainfo.xml index 4ac5f88e14..2d48dc4dc3 100644 --- a/scripts/flatpak/chat.simplex.simplex.metainfo.xml +++ b/scripts/flatpak/chat.simplex.simplex.metainfo.xml @@ -38,6 +38,41 @@ + + https://simplex.chat/blog/20240814-simplex-chat-vision-funding-v6-private-routing-new-user-experience.html + +

New in v6.0.1-4:

+
    +
  • reduce traffic and battery usage on unstable networks.
  • +
  • only offer the next versions for update, based on SerVer ordering.
  • +
  • UI fixes.
  • +
  • reduce app memory usage and start time.
  • +
  • faster sending of files to groups.
  • +
  • fix rare delivery bug.
  • +
+

New in v6.0:

+

New chat experience:

+
    +
  • connect to your friends faster.
  • +
  • archive contacts to chat later.
  • +
  • delete up to 20 messages at once.
  • +
  • increase font size.
  • +
+

New media options:

+
    +
  • play from the chat list.
  • +
  • blur for better privacy.
  • +
+

Private routing:

+
    +
  • it protects your IP address and connections and is now enabled by default.
  • +
+

Connection and servers information:

+
    +
  • to control your network status and usage.
  • +
+
+
https://simplex.chat/blog/20240814-simplex-chat-vision-funding-v6-private-routing-new-user-experience.html From 33895b0330fd9e32dc9bc1e69bc15d54a9207cb2 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Tue, 3 Sep 2024 09:59:40 +0300 Subject: [PATCH 15/19] ios: show received messages using checkmark with slash (#4816) * ios: show received messages using checkmark with slash * update message info view * cleanup * remove dead arguments * Revert "remove dead arguments" This reverts commit 1fc07669c785dde960c77ee54026004871706acf. * remove status icon * cleanup * update assets * tweak checkmark * fix space, rename --------- Co-authored-by: Evgeny Poberezkin --- .../checkmark.2.symbolset/Contents.json | 12 + .../checkmark.2.symbolset/checkmark.2.svg | 227 ++++++++++++++++++ .../checkmark.wide.symbolset/Contents.json | 12 + .../checkmark.wide.svg | 218 +++++++++++++++++ .../Views/Chat/ChatItem/CIMetaView.swift | 57 ++--- .../Shared/Views/Chat/ChatItemInfoView.swift | 16 +- apps/ios/SimpleXChat/ChatTypes.swift | 54 +++-- 7 files changed, 514 insertions(+), 82 deletions(-) create mode 100644 apps/ios/Shared/Assets.xcassets/checkmark.2.symbolset/Contents.json create mode 100644 apps/ios/Shared/Assets.xcassets/checkmark.2.symbolset/checkmark.2.svg create mode 100644 apps/ios/Shared/Assets.xcassets/checkmark.wide.symbolset/Contents.json create mode 100644 apps/ios/Shared/Assets.xcassets/checkmark.wide.symbolset/checkmark.wide.svg diff --git a/apps/ios/Shared/Assets.xcassets/checkmark.2.symbolset/Contents.json b/apps/ios/Shared/Assets.xcassets/checkmark.2.symbolset/Contents.json new file mode 100644 index 0000000000..8e38b499dd --- /dev/null +++ b/apps/ios/Shared/Assets.xcassets/checkmark.2.symbolset/Contents.json @@ -0,0 +1,12 @@ +{ + "info": { + "author": "xcode", + "version": 1 + }, + "symbols": [ + { + "filename": "checkmark.2.svg", + "idiom": "universal" + } + ] +} \ No newline at end of file diff --git a/apps/ios/Shared/Assets.xcassets/checkmark.2.symbolset/checkmark.2.svg b/apps/ios/Shared/Assets.xcassets/checkmark.2.symbolset/checkmark.2.svg new file mode 100644 index 0000000000..577fa1db76 --- /dev/null +++ b/apps/ios/Shared/Assets.xcassets/checkmark.2.symbolset/checkmark.2.svg @@ -0,0 +1,227 @@ + + + checkmark.2 + + + + + + + Weight/Scale Variations + + + Ultralight + + + Thin + + + Light + + + Regular + + + Medium + + + Semibold + + + Bold + + + Heavy + + + Black + + + + + + + + + + + + + Design Variations + + + Symbols are supported in up to nine weights and three scales. + + + For optimal layout with text and other symbols, vertically align + + + symbols with the adjacent text. + + + + + + + + + Margins + + + Leading and trailing margins on the left and right side of each symbol + + + + can be adjusted by modifying the x-location of the margin guidelines. + + + + Modifications are automatically applied proportionally to all + + + scales and weights. + + + + + + Exporting + + + Symbols should be outlined when exporting to ensure the + + + design is preserved when submitting to Xcode. + + + Template v.5.0 + + + Requires Xcode 15 or greater + + + Generated from double.checkmark + + + Typeset at 100.0 points + + + Small + + + Medium + + + Large + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/ios/Shared/Assets.xcassets/checkmark.wide.symbolset/Contents.json b/apps/ios/Shared/Assets.xcassets/checkmark.wide.symbolset/Contents.json new file mode 100644 index 0000000000..11a91cb811 --- /dev/null +++ b/apps/ios/Shared/Assets.xcassets/checkmark.wide.symbolset/Contents.json @@ -0,0 +1,12 @@ +{ + "info": { + "author": "xcode", + "version": 1 + }, + "symbols": [ + { + "filename": "checkmark.wide.svg", + "idiom": "universal" + } + ] +} \ No newline at end of file diff --git a/apps/ios/Shared/Assets.xcassets/checkmark.wide.symbolset/checkmark.wide.svg b/apps/ios/Shared/Assets.xcassets/checkmark.wide.symbolset/checkmark.wide.svg new file mode 100644 index 0000000000..b5dfc6b3de --- /dev/null +++ b/apps/ios/Shared/Assets.xcassets/checkmark.wide.symbolset/checkmark.wide.svg @@ -0,0 +1,218 @@ + + + checkmark.wide + + + + + + + Weight/Scale Variations + + + Ultralight + + + Thin + + + Light + + + Regular + + + Medium + + + Semibold + + + Bold + + + Heavy + + + Black + + + + + + + + + + + + + Design Variations + + + Symbols are supported in up to nine weights and three scales. + + + For optimal layout with text and other symbols, vertically align + + + symbols with the adjacent text. + + + + + + + + + Margins + + + Leading and trailing margins on the left and right side of each symbol + + + + can be adjusted by modifying the x-location of the margin guidelines. + + + + Modifications are automatically applied proportionally to all + + + scales and weights. + + + + + + Exporting + + + Symbols should be outlined when exporting to ensure the + + + design is preserved when submitting to Xcode. + + + Template v.5.0 + + + Requires Xcode 15 or greater + + + Generated from double.checkmark + + + Typeset at 100.0 points + + + Small + + + Medium + + + Large + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift index 3f2ec8f38e..719c1cabd0 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift @@ -25,41 +25,22 @@ struct CIMetaView: View { if chatItem.isDeletedContent { chatItem.timestampText.font(.caption).foregroundColor(metaColor) } else { - let meta = chatItem.meta - let ttl = chat.chatInfo.timedMessagesTTL - let encrypted = chatItem.encryptedFile - switch meta.itemStatus { - case let .sndSent(sndProgress): - switch sndProgress { - case .complete: ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .sent, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp) - case .partial: ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .sent, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp) - } - case let .sndRcvd(_, sndProgress): - switch sndProgress { - case .complete: - ZStack { - ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .rcvd1, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp) - ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .rcvd2, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp) - } - case .partial: - ZStack { - ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .rcvd1, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp) - ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .rcvd2, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp) - } - } - default: - ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp) - } + ciMetaText( + chatItem.meta, + chatTTL: chat.chatInfo.timedMessagesTTL, + encrypted: chatItem.encryptedFile, + color: chatItem.meta.itemStatus.sndProgress == .partial + ? paleMetaColor + : metaColor, + showStatus: showStatus, + showEdited: showEdited, + showViaProxy: showSentViaProxy, + showTimesamp: showTimestamp + ) } } } -enum SentCheckmark { - case sent - case rcvd1 - case rcvd2 -} - func ciMetaText( _ meta: CIMeta, chatTTL: Int?, @@ -67,7 +48,6 @@ func ciMetaText( color: Color = .clear, primaryColor: Color = .accentColor, transparent: Bool = false, - sent: SentCheckmark? = nil, showStatus: Bool = true, showEdited: Bool = true, showViaProxy: Bool, @@ -89,17 +69,8 @@ func ciMetaText( r = r + statusIconText("arrow.forward", color.opacity(0.67)).font(.caption2) } if showStatus { - if let (icon, statusColor) = meta.statusIcon(color, primaryColor) { - let t = Text(Image(systemName: icon)).font(.caption2) - let gap = Text(" ").kerning(-1.25) - let t1 = t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67)) - switch sent { - case nil: r = r + t1 - case .sent: r = r + t1 + gap - case .rcvd1: r = r + t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67)) + gap - case .rcvd2: r = r + gap + t1 - } - r = r + Text(" ") + if let (image, statusColor) = meta.itemStatus.statusIcon(color, primaryColor) { + r = r + Text(image).foregroundColor(transparent ? .clear : statusColor) + Text(" ") } else if !meta.disappearing { r = r + statusIconText("circlebadge.fill", .clear) + Text(" ") } diff --git a/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift b/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift index f6a856dad1..62ea607d27 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift @@ -450,20 +450,8 @@ struct ChatItemInfoView: View { .foregroundColor(theme.colors.secondary).opacity(0.67) } let v = Group { - let (icon, statusColor) = status.statusIcon(theme.colors.secondary, theme.colors.primary) - switch status { - case .rcvd: - ZStack(alignment: .trailing) { - Image(systemName: icon) - .foregroundColor(statusColor.opacity(0.67)) - .padding(.trailing, 6) - Image(systemName: icon) - .foregroundColor(statusColor.opacity(0.67)) - } - default: - Image(systemName: icon) - .foregroundColor(statusColor) - } + let (image, statusColor) = status.statusIcon(theme.colors.secondary, theme.colors.primary) + image.foregroundColor(statusColor) } if let (title, text) = status.statusInfo { diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 07340bb963..105edd725f 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -2723,10 +2723,6 @@ public struct CIMeta: Decodable, Hashable { return false } - public func statusIcon(_ metaColor: Color/* = .secondary*/, _ primaryColor: Color = .accentColor) -> (String, Color)? { - itemStatus.statusIcon(metaColor, primaryColor) - } - public static func getSample(_ id: Int64, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, itemDeleted: CIDeleted? = nil, itemEdited: Bool = false, itemLive: Bool = false, deletable: Bool = true, editable: Bool = true) -> CIMeta { CIMeta( itemId: id, @@ -2794,21 +2790,29 @@ public enum CIStatus: Decodable, Hashable { } } - public func statusIcon(_ metaColor: Color/* = .secondary*/, _ primaryColor: Color = .accentColor) -> (String, Color)? { + public func statusIcon(_ metaColor: Color, _ primaryColor: Color = .accentColor) -> (Image, Color)? { switch self { - case .sndNew: return nil - case .sndSent: return ("checkmark", metaColor) + case .sndNew: nil + case .sndSent: (Image("checkmark.wide"), metaColor) case let .sndRcvd(msgRcptStatus, _): switch msgRcptStatus { - case .ok: return ("checkmark", metaColor) - case .badMsgHash: return ("checkmark", .red) + case .ok: (Image("checkmark.2"), metaColor) + case .badMsgHash: (Image("checkmark.2"), .red) } - case .sndErrorAuth: return ("multiply", .red) - case .sndError: return ("multiply", .red) - case .sndWarning: return ("exclamationmark.triangle.fill", .orange) - case .rcvNew: return ("circlebadge.fill", primaryColor) - case .rcvRead: return nil - case .invalid: return ("questionmark", metaColor) + case .sndErrorAuth: (Image(systemName: "multiply"), .red) + case .sndError: (Image(systemName: "multiply"), .red) + case .sndWarning: (Image(systemName: "exclamationmark.triangle.fill"), .orange) + case .rcvNew: (Image(systemName: "circlebadge.fill"), primaryColor) + case .rcvRead: nil + case .invalid: (Image(systemName: "questionmark"), metaColor) + } + } + + public var sndProgress: SndCIStatusProgress? { + switch self { + case let .sndSent(sndProgress): sndProgress + case let .sndRcvd(_ , sndProgress): sndProgress + default: nil } } @@ -2903,20 +2907,20 @@ public enum GroupSndStatus: Decodable, Hashable { case warning(agentError: SndError) case invalid(text: String) - public func statusIcon(_ metaColor: Color/* = .secondary*/, _ primaryColor: Color = .accentColor) -> (String, Color) { + public func statusIcon(_ metaColor: Color, _ primaryColor: Color = .accentColor) -> (Image, Color) { switch self { - case .new: return ("ellipsis", metaColor) - case .forwarded: return ("chevron.forward.2", metaColor) - case .inactive: return ("person.badge.minus", metaColor) - case .sent: return ("checkmark", metaColor) + case .new: (Image(systemName: "ellipsis"), metaColor) + case .forwarded: (Image(systemName: "chevron.forward.2"), metaColor) + case .inactive: (Image(systemName: "person.badge.minus"), metaColor) + case .sent: (Image("checkmark.wide"), metaColor) case let .rcvd(msgRcptStatus): switch msgRcptStatus { - case .ok: return ("checkmark", metaColor) - case .badMsgHash: return ("checkmark", .red) + case .ok: (Image("checkmark.2"), metaColor) + case .badMsgHash: (Image("checkmark.2"), .red) } - case .error: return ("multiply", .red) - case .warning: return ("exclamationmark.triangle.fill", .orange) - case .invalid: return ("questionmark", metaColor) + case .error: (Image(systemName: "multiply"), .red) + case .warning: (Image(systemName: "exclamationmark.triangle.fill"), .orange) + case .invalid: (Image(systemName: "questionmark"), metaColor) } } From 31c4ff270584bf679e9256ff02df0874c85d62a0 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:36:01 +0000 Subject: [PATCH 16/19] android, desktop: group info remembers scroll position and search (#4817) --- .../views/chat/group/GroupChatInfoView.kt | 11 +++---- .../common/views/helpers/SearchTextField.kt | 6 ---- .../common/views/newchat/NewChatSheet.kt | 32 ++++++++++++++----- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt index 81a0de7bb9..a14d227074 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt @@ -40,7 +40,7 @@ import kotlinx.coroutines.launch const val SMALL_GROUPS_RCPS_MEM_LIMIT: Int = 20 @Composable -fun GroupChatInfoView(chatModel: ChatModel, rhId: Long?, chatId: String, groupLink: String?, groupLinkMemberRole: GroupMemberRole?, onGroupLinkUpdated: (Pair?) -> Unit, close: () -> Unit, onSearchClicked: () -> Unit) { +fun ModalData.GroupChatInfoView(chatModel: ChatModel, rhId: Long?, chatId: String, groupLink: String?, groupLinkMemberRole: GroupMemberRole?, onGroupLinkUpdated: (Pair?) -> Unit, close: () -> Unit, onSearchClicked: () -> Unit) { BackHandler(onBack = close) // TODO derivedStateOf? val chat = chatModel.chats.value.firstOrNull { ch -> ch.id == chatId && ch.remoteHostId == rhId } @@ -249,9 +249,8 @@ fun AddGroupMembersButton( ) } - @Composable -fun GroupChatInfoLayout( +fun ModalData.GroupChatInfoLayout( chat: Chat, groupInfo: GroupInfo, currentUser: User, @@ -272,12 +271,12 @@ fun GroupChatInfoLayout( close: () -> Unit = { ModalManager.closeAllModalsEverywhere()}, onSearchClicked: () -> Unit ) { - val listState = rememberLazyListState() + val listState = remember { appBarHandler.listState } val scope = rememberCoroutineScope() KeyChangeEffect(chat.id) { scope.launch { listState.scrollToItem(0) } } - val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) } + val searchText = remember { stateGetOrPut("searchText") { TextFieldValue() } } val filteredMembers = remember(members) { derivedStateOf { val s = searchText.value.text.trim().lowercase() @@ -674,7 +673,7 @@ private fun SearchRowView( @Composable fun PreviewGroupChatInfoLayout() { SimpleXTheme { - GroupChatInfoLayout( + ModalData().GroupChatInfoLayout( chat = Chat( remoteHostId = null, chatInfo = ChatInfo.Direct.sampleData, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SearchTextField.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SearchTextField.kt index c6d5d6ad16..60dceab4ad 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SearchTextField.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SearchTextField.kt @@ -71,12 +71,6 @@ fun SearchTextField( } } - DisposableEffect(Unit) { - onDispose { - if (searchText.value.text.isNotEmpty()) onValueChange("") - } - } - val colors = TextFieldDefaults.textFieldColors( backgroundColor = Color.Unspecified, textColor = MaterialTheme.colors.onBackground, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index 99ba7be8d2..7a9fec100d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -36,11 +36,13 @@ import chat.simplex.common.views.chatlist.ScrollDirection import chat.simplex.common.views.contacts.* import chat.simplex.common.views.helpers.* import chat.simplex.res.MR +import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter import java.net.URI @Composable -fun NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) { +fun ModalData.NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) { val oneHandUI = remember { appPrefs.oneHandUI.state } val keyboardState by getKeyboardState() val showToolbarInOneHandUI = remember { derivedStateOf { keyboardState == KeyboardState.Closed && oneHandUI.value } } @@ -111,10 +113,8 @@ private fun filterContactTypes(c: List, contactTypes: List): return c.filter { chat -> contactTypes.contains(chatContactType(chat)) } } -private var lazyListState = 0 to 0 - @Composable -private fun NewChatSheetLayout( +private fun ModalData.NewChatSheetLayout( rh: RemoteHostInfo?, addContact: () -> Unit, scanPaste: () -> Unit, @@ -122,7 +122,23 @@ private fun NewChatSheetLayout( close: () -> Unit, ) { val oneHandUI = remember { appPrefs.oneHandUI.state } - val listState = rememberLazyListState(lazyListState.first, lazyListState.second) + val listState = remember { appBarHandler.listState } + // This is workaround of an issue when position of a list is not restored (when going back to that screen) when a header exists. + // Upon returning back, this code returns correct index and position if number of items is the same + LaunchedEffect(Unit) { + val prevIndex = listState.firstVisibleItemIndex + val prevOffset = listState.firstVisibleItemScrollOffset + val total = listState.layoutInfo.totalItemsCount + if (prevIndex == 0 && prevOffset == 0) return@LaunchedEffect + snapshotFlow { listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset } + .filter { it == 0 to 0 } + .collect { + if (total <= listState.layoutInfo.totalItemsCount) { + listState.scrollToItem(prevIndex, prevOffset) + } + cancel() + } + } val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } val searchShowingSimplexLink = remember { mutableStateOf(false) } val searchChatFilteredBySimplexLink = remember { mutableStateOf(null) } @@ -536,7 +552,7 @@ private fun contactTypesSearchTargets(baseContactTypes: List, searc } @Composable -private fun DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Unit, close: () -> Unit) { +private fun ModalData.DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Unit, close: () -> Unit) { val oneHandUI = remember { appPrefs.oneHandUI.state } val keyboardState by getKeyboardState() val showToolbarInOneHandUI = remember { derivedStateOf { keyboardState == KeyboardState.Closed && oneHandUI.value } } @@ -558,7 +574,7 @@ private fun DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Un } } ) { contentPadding -> - val listState = rememberLazyListState(lazyListState.first, lazyListState.second) + val listState = remember { appBarHandler.listState } val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } val searchShowingSimplexLink = remember { mutableStateOf(false) } val searchChatFilteredBySimplexLink = remember { mutableStateOf(null) } @@ -723,6 +739,6 @@ fun ActionButton( @Composable private fun PreviewNewChatSheet() { SimpleXTheme { - NewChatSheet(rh = null, close = {}) + ModalData().NewChatSheet(rh = null, close = {}) } } From 2089fd853981b3910fbad943c495473343a8dca4 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:36:41 +0000 Subject: [PATCH 17/19] android, desktop: remove slash from strings (#4818) --- .../src/commonMain/resources/MR/ar/strings.xml | 10 +++++----- .../src/commonMain/resources/MR/base/strings.xml | 6 +++--- .../src/commonMain/resources/MR/bg/strings.xml | 12 ++++++------ .../src/commonMain/resources/MR/cs/strings.xml | 6 +++--- .../src/commonMain/resources/MR/de/strings.xml | 8 ++++---- .../src/commonMain/resources/MR/es/strings.xml | 6 +++--- .../src/commonMain/resources/MR/fi/strings.xml | 6 +++--- .../src/commonMain/resources/MR/fr/strings.xml | 2 +- .../src/commonMain/resources/MR/it/strings.xml | 8 ++++---- .../src/commonMain/resources/MR/iw/strings.xml | 10 +++++----- .../src/commonMain/resources/MR/ko/strings.xml | 8 ++++---- .../src/commonMain/resources/MR/lt/strings.xml | 4 ++-- .../src/commonMain/resources/MR/ml/strings.xml | 2 +- .../src/commonMain/resources/MR/nl/strings.xml | 6 +++--- .../src/commonMain/resources/MR/pl/strings.xml | 6 +++--- .../src/commonMain/resources/MR/pt-rBR/strings.xml | 6 +++--- .../src/commonMain/resources/MR/pt/strings.xml | 2 +- .../src/commonMain/resources/MR/ru/strings.xml | 8 ++++---- .../src/commonMain/resources/MR/th/strings.xml | 6 +++--- .../src/commonMain/resources/MR/tr/strings.xml | 6 +++--- .../src/commonMain/resources/MR/uk/strings.xml | 4 ++-- .../src/commonMain/resources/MR/zh-rCN/strings.xml | 2 +- .../src/commonMain/resources/MR/zh-rTW/strings.xml | 4 ++-- 23 files changed, 69 insertions(+), 69 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml index 7fb812ade9..8f4b0158a7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml @@ -22,8 +22,8 @@ ينطبق هذا الإعداد على الرسائل الموجودة في ملف تعريف الدردشة الحالي الخاص بك منصة الرسائل والتطبيقات تحمي خصوصيتك وأمنك. يتم مشاركة ملف التعريف مع جهات اتصالك فقط. - سيتم تغيير الدور إلى \"%s\". سيتم إبلاغ كل فرد في المجموعة. - سيتم تغيير الدور إلى \"%s\". سيستلم العضو دعوة جديدة. + سيتم تغيير الدور إلى "%s". سيتم إبلاغ كل فرد في المجموعة. + سيتم تغيير الدور إلى "%s". سيستلم العضو دعوة جديدة. خوادم الاتصالات الجديدة لملف تعريف الدردشة الحالي الخاص بك سيتم تغيير عنوان الاستلام إلى خادم مختلف. سيتم إكمال تغيير العنوان بعد اتصال المرسل بالإنترنت. هذا الرابط ليس رابط اتصال صالح! @@ -767,7 +767,7 @@ لم تٌحدد جهات اتصال يمكّن للمشرف الآن: \n- حذف رسائل الأعضاء. -\n- تعطيل الأعضاء (دور \"المراقب\") +\n- تعطيل الأعضاء (دور "المراقب") خدمة الإشعار غير مفعّل` مفعل @@ -1076,7 +1076,7 @@ إيقاف الملف التوقف عن إرسال الملف؟ عنوان SimpleX - استخدم مضيفي .onion إلى \"لا\" إذا كان وكيل SOCKS لا يدعمها.]]> + استخدم مضيفي .onion إلى "لا" إذا كان وكيل SOCKS لا يدعمها.]]> مشاركة مع جهات الاتصال إيقاف التشغيل؟ إعدادات وكيل SOCKS @@ -1406,7 +1406,7 @@ سطح المكتب متصل اتصل تلقائيًا عنوان سطح المكتب - وضّع علامة \"محذوفة\" على %d من الرسائل + وضّع علامة "محذوفة" على %d من الرسائل اكتشف عبر الشبكة المحلية اتصل عبر الرابط؟ اتصل بنفسك؟ diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index f5272ce7fc..1a3eb2c72f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1556,8 +1556,8 @@ Change Switch Change group role? - The role will be changed to \"%s\". Everyone in the group will be notified. - The role will be changed to \"%s\". The member will receive a new invitation. + The role will be changed to "%s". Everyone in the group will be notified. + The role will be changed to "%s". The member will receive a new invitation. Connect directly? Сonnection request will be sent to this group member. Error removing member @@ -1893,7 +1893,7 @@ Audio and video calls Support bluetooth and other improvements. Group moderation - Now admins can:\n- delete members\' messages.\n- disable members (\"observer\" role) + Now admins can:\n- delete members\' messages.\n- disable members ("observer" role) Group welcome message Set the message shown to new members! Further reduced battery usage diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml index d43aee7c8a..54eb0e9034 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml @@ -482,7 +482,7 @@ Изпращането на потвърждениe за доставка ще бъде активирано за всички контакти във всички видими чат профили. Изпращане на потвърждениe за доставка Можете да активирате по-късно през Настройки - Можете да ги активирате по-късно през настройките за \"Поверителност и сигурност\" на приложението. + Можете да ги активирате по-късно през настройките за "Поверителност и сигурност" на приложението. Предупреждение: Може да загубите някои данни! Въведи правилна парола. активирано за вас @@ -517,7 +517,7 @@ криптирането е съгласувано за %s Редактирай групов профил Изчезва в: %s - Ролята ще бъде променена на \"%s\". Членът ще получи нова покана. + Ролята ще бъде променена на "%s". Членът ще получи нова покана. директна Предоговори криптирането Въведи име на групата: @@ -918,7 +918,7 @@ Членът ще бъде премахнат от групата - това не може да бъде отменено! няма текст Острани член - Ролята ще бъде променена на \"%s\". Всички в групата ще бъдат уведомени. + Ролята ще бъде променена на "%s". Всички в групата ще бъдат уведомени. Само данни за локален профил Профилни и сървърни връзки Без звук @@ -936,7 +936,7 @@ Защитете чат профилите с парола! Сега администраторите могат: \n- да изтриват съобщения на членове. -\n- да деактивират членове (роля \"наблюдател\") +\n- да деактивират членове (роля "наблюдател") Очаквайте скоро още подобрения! Полски интерфейс Реакции на съобщения @@ -1155,7 +1155,7 @@ Този линк не е валиден линк за връзка! Вашите чат профили Сървърите за нови връзки на текущия ви чат профил - За да покажете скрития профил, въведете пълната парола в полето за търсене на страницата \"Вашите чат профили\". + За да покажете скрития профил, въведете пълната парола в полето за търсене на страницата "Вашите чат профили". Профилът се споделя само с вашите контакти. Това действие не може да бъде отменено - всички получени и изпратени файлове и медия ще бъдат изтрити. Снимките с ниска разделителна способност ще бъдат запазени. Докосни за активиране на профил. @@ -1646,7 +1646,7 @@ Квантово устойчиво криптиране Миграция на данните от приложението Мигрирайте към друго устройство чрез QR код. - Обаждания \"картина в картина\" + Обаждания "картина в картина" По-безопасни групи Администраторите могат да блокират член за всички. Подробности за линка се изтеглят diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml index 591643a4da..0c4e78a269 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml @@ -462,7 +462,7 @@ odešel Vyčistit Přepnout - Role bude změněna na \"%s\". Všichni ve skupině budou informováni. + Role bude změněna na "%s". Všichni ve skupině budou informováni. Chyba při odebrání člena Chyba při ukládání profilu skupiny vteřiny @@ -857,7 +857,7 @@ Role Změnit roli Změnit - Role bude změněna na \"%s\". Člen obdrží novou pozvánku. + Role bude změněna na "%s". Člen obdrží novou pozvánku. Chyba při změně role přímo Odesíláno přes @@ -972,7 +972,7 @@ Další vylepšení již brzy! Nyní mohou správci: \n- mazat zprávy členů. -\n- zakázat členy (role \"pozorovatel\") +\n- zakázat členy (role "pozorovatel") Uložit heslo profilu Ztlumit Chraňte své chat profily heslem! diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml index 64b7f9d8f7..897ea64be8 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml @@ -792,8 +792,8 @@ Ändern Wechseln Die Mitgliederrolle ändern? - Die Mitgliederrolle wird auf \"%s\" geändert. Alle Mitglieder der Gruppe werden benachrichtigt. - Die Mitgliederrolle wird auf \"%s\" geändert. Das Mitglied wird eine neue Einladung erhalten. + Die Mitgliederrolle wird auf "%s" geändert. Alle Mitglieder der Gruppe werden benachrichtigt. + Die Mitgliederrolle wird auf "%s" geändert. Das Mitglied wird eine neue Einladung erhalten. Fehler beim Entfernen des Mitglieds Fehler beim Ändern der Rolle Gruppe @@ -1074,7 +1074,7 @@ Sie können Anrufe und Benachrichtigungen auch von stummgeschalteten Profilen empfangen, solange diese aktiv sind. Begrüßungsmeldung Sie können ein Benutzerprofil verbergen oder stummschalten – für das Menü gedrückt halten. - Geben Sie ein vollständiges Passwort in das Suchfeld auf der Seite \"Ihre Chat-Profile\" ein, um Ihr verborgenes Profil zu sehen. + Geben Sie ein vollständiges Passwort in das Suchfeld auf der Seite "Ihre Chat-Profile" ein, um Ihr verborgenes Profil zu sehen. Migrations-Bestätigung ungültig Aktualisieren und den Chat öffnen Datenbank-Aktualisierungen bestätigen @@ -1151,7 +1151,7 @@ SOCKS-Proxy nutzen SimpleX-Sperrmodus SimpleX-Sperre ist nicht aktiviert! - Verwende .onion-Hosts auf \"Nein\", wenn der SOCKS-Proxy sie nicht unterstützt.]]> + Verwende .onion-Hosts auf "Nein", wenn der SOCKS-Proxy sie nicht unterstützt.]]> Bestätigen System Sie können nicht überprüft werden – bitte versuchen Sie es nochmal. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml index bc27b0a29f..9ba8c60f87 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml @@ -726,7 +726,7 @@ envío no autorizado Escribe un nombre para el contacto Error desconocido - El rol del miembro cambiará a \"%s\" y se notificará al grupo. + El rol del miembro cambiará a "%s" y se notificará al grupo. La seguridad de SimpleX Chat ha sido auditada por Trail of Bits. Los mensajes enviados se eliminarán una vez transcurrido el tiempo establecido. Mensajes de chat SimpleX @@ -814,7 +814,7 @@ Actualizar contraseña base de datos Pulsa para unirte en modo incógnito Cambiar - El rol del miembro cambiará a \"%s\" y recibirá una invitación nueva. + El rol del miembro cambiará a "%s" y recibirá una invitación nueva. Actualizar ¿Actualizar la configuración de red\? Intentando conectar con el servidor para recibir mensajes de este contacto. @@ -992,7 +992,7 @@ Seguirás recibiendo llamadas y notificaciones de los perfiles silenciados cuando estén activos. Ahora los administradores pueden: \n- eliminar mensajes de los miembros. -\n- desactivar el rol miembro (a rol \"observador\") +\n- desactivar el rol miembro (a rol "observador") Para hacer visible tu perfil oculto, introduce la contraseña completa en el campo de búsqueda del menú Mis perfiles. Actualización de la base de datos Volviendo a versión anterior de la base de datos diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml index 8200d8a0ff..c3ea7d89f7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml @@ -757,7 +757,7 @@ Lisää parannuksia on tulossa pian! Nyt järjestelmänvalvojat voivat: \n- poistaa jäsenten viestit. -\n- poista jäsenet käytöstä (\"tarkkailija\" rooli) +\n- poista jäsenet käytöstä ("tarkkailija" rooli) Tallenna ja ilmoita ryhmän jäsenille Lopeta Pysäytä keskustelut viedäksesi, tuodaksesi tai poistaaksesi keskustelujen tietokannan. Et voi vastaanottaa ja lähettää viestejä, kun keskustelut on pysäytetty. @@ -1108,8 +1108,8 @@ Viestintä- ja sovellusalusta, joka suojaa yksityisyyttäsi ja tietoturvaasi. videopuhelu %1$s JÄSENET - Rooli muuttuu muotoon \"%s\". Kaikille ryhmän jäsenille ilmoitetaan asiasta. - Rooli muuttuu muotoon \"%s\". Jäsen saa uuden kutsun. + Rooli muuttuu muotoon "%s". Kaikille ryhmän jäsenille ilmoitetaan asiasta. + Rooli muuttuu muotoon "%s". Jäsen saa uuden kutsun. Ääniviestit ovat kiellettyjä tässä keskustelussa. Ääniviestit Yritetään muodostaa yhteys palvelimeen, jota käytetään viestien vastaanottamiseen tältä kontaktilta. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml index 02487f8ba7..553f70e31a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml @@ -972,7 +972,7 @@ Profils de chat cachés Désormais, les administrateurs peuvent : \n- supprimer les messages des membres. -\n- désactiver des membres (rôle \"observateur\") +\n- désactiver des membres (rôle "observateur") Enregistrer le message d\'accueil ? Choisissez un message à l\'attention des nouveaux membres ! Masquer le profil diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml index 34ee1721f0..1bc9f6283f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml @@ -822,8 +822,8 @@ Sistema Scadenza connessione TCP Completamente decentralizzato: visibile solo ai membri. - Il ruolo verrà cambiato in \"%s\". Tutti i membri del gruppo riceveranno una notifica. - Il ruolo verrà cambiato in \"%s\". Il membro riceverà un nuovo invito. + Il ruolo verrà cambiato in "%s". Tutti i membri del gruppo riceveranno una notifica. + Il ruolo verrà cambiato in "%s". Il membro riceverà un nuovo invito. Aggiorna Aggiornare le impostazioni di rete\? L\'aggiornamento delle impostazioni riconnetterà il client a tutti i server. @@ -978,11 +978,11 @@ Grazie agli utenti – contribuite via Weblate! Password del profilo nascosta Salva la password del profilo - Per rivelare il tuo profilo nascosto, inserisci una password completa in un campo di ricerca nella pagina \"I tuoi profili di chat\". + Per rivelare il tuo profilo nascosto, inserisci una password completa in un campo di ricerca nella pagina "I tuoi profili di chat". Password per mostrare Ora gli amministratori possono: \n- eliminare i messaggi dei membri. -\n- disattivare i membri (ruolo \"osservatore\") +\n- disattivare i membri (ruolo "osservatore") Nascondi il profilo Conferma password Errore nell\'aggiornamento della privacy dell\'utente diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml index e4901dd875..d207057d0c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml @@ -1015,7 +1015,7 @@ הקישו כדי להצטרף תום זמן חיבור TCP האפליקציה בודקת הודעות חדשות מעת לעת - היא משתמשת בכמה אחוזים מהסוללה ביום. האפליקציה לא משתמשת בהתראות דחיפה - נתונים מהמכשיר שלך לא נשלחים לשרתים. - התפקיד ישתנה ל־\"%s\". כל חברי הקבוצה יקבלו הודעה על כך. + התפקיד ישתנה ל־"%s". כל חברי הקבוצה יקבלו הודעה על כך. כדי להתחבר באמצעות קישור פלטפורמת ההודעות והיישומים המגנה על הפרטיות והאבטחה שלך. המזהה של ההודעה הבאה שגוי (קטן או שווה להודעה הקודמת). @@ -1027,7 +1027,7 @@ תודה שהתקנתם את SimpleX Chat! קישור זה אינו קישור חיבור תקין! צבעי ערכת נושא - התפקיד ישתנה ל־\"%s\". החבר יקבל הזמנה חדשה. + התפקיד ישתנה ל־"%s". החבר יקבל הזמנה חדשה. השרתים לחיבורים חדשים של פרופיל הצ׳אט הנוכחי שלך הפלטפורמה הראשונה ללא כל מזהי משתמש - פרטית בעיצובה. הדור הבא של תקשורת פרטית @@ -1836,7 +1836,7 @@ מערכת שגיאה בהצגת התראה, צור קשר עם המפתחים שגיאה בהתחברות לשרת %1$s, אנא נסה מאוחר יותר - אין עדיין חיבור ישיר, ההודעה תעובר ע\"י מנהל. + אין עדיין חיבור ישיר, ההודעה תעובר ע"י מנהל. חבר לא פעיל שרתי XFTP אחרים הראה אחוזים @@ -1920,11 +1920,11 @@ קבצים אין מידע, נסה לרענן מידע על השרתים - התקבל סה\"כ + התקבל סה"כ התקבלו שגיאות התחבר מחדש שלח הודעות - נשלח בסה\"כ + נשלח בסה"כ שרת SMP שרת XFTP חלש diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml index ffd62b4755..639a888bc9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml @@ -634,7 +634,7 @@ 메시지 이 설정은 현재 내 프로필의 메시지에 적용되어요. 멤버 - 역할이 \"%s\"(으)로 변경되고, 회원은 새로운 초대를 받게 될 거예요. + 역할이 "%s"(으)로 변경되고, 회원은 새로운 초대를 받게 될 거예요. 이 채팅에서는 메시지 영구 삭제가 허용되지 않았어요. 나가기 큰 파일! @@ -675,11 +675,11 @@ 그룹에서 나갈까요\? 데이터베이스 버전이 앱보다 최신이지만, 다음에 대한 다운 마이그레이션 없음: %s 멤버가 그룹에서 제거되어요. 이 작업은 되돌릴 수 없어요! - 역할이 \"%s\"(으)로 변경되어요. 그룹의 모든 멤버에게 알림이 전송됩니다. + 역할이 "%s"(으)로 변경되어요. 그룹의 모든 멤버에게 알림이 전송됩니다. 기본값으로 재설정 메시지 내용 대화 상대 이름 및 메시지 표시 - 나만 메시지를 영구 삭제할 수 있어요(대화 상대는 \"삭제됨\" 표시만 할 수 있음). + 나만 메시지를 영구 삭제할 수 있어요(대화 상대는 "삭제됨" 표시만 할 수 있음). 이 링크를 보낸 상대에게 프로필이 전송될 거예요. 파일 수신은 아직 지원되지 않아요. 올바른 링크를 사용했는지 확인하거나 상대에게 다른 링크를 보내달라고 말해 주세요 @@ -714,7 +714,7 @@ 대화 상대만 음성 메시지를 보낼 수 있어요. 메시지 영구 삭제 허용되지 않음. 음성 메시지 허용되지 않음. - 상대만 메시지를 영구 삭제할 수 있어요(나는 \"삭제됨\"으로 표시만 할 수 있음). + 상대만 메시지를 영구 삭제할 수 있어요(나는 "삭제됨"으로 표시만 할 수 있음). 그룹 소유자만 음성 메시지를 사용 가능하도록 설정할 수 있어요. 일회성 초대 링크 붙여넣기 diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml index 6139eb5133..8d8d73b206 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml @@ -600,7 +600,7 @@ Nepavyko pakviesti kontakto! Pagal pokalbių profilį (numatytieji nustatymai) arba pagal ryšį (BETA). Naudoja daugiau baterijos! Fono paslauga veikia visada - pranešimai rodomi, kai tik atsiranda žinučių.]]> - Negalima pasiekti \"Keystore\", kad išsaugotumėte duomenų bazės slaptažodį + Negalima pasiekti "Keystore", kad išsaugotumėte duomenų bazės slaptažodį Atšaukti failo peržiūrą Atšaukti vaizdo peržiūrą Duomenų bazės ID: %d @@ -1484,7 +1484,7 @@ Nėra pristatymo informacijos Dabar administratoriai gali: \n- ištrinti narių žinutes. -\n- išjungti narius (\"stebėtojas\" rolė) +\n- išjungti narius ("stebėtojas" rolė) įj. Nebemėgti Nustatymų atnaujinimas perjungs klientą iš naujo prie visų serverių. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml index d97cf4b7ad..dc692c1968 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml @@ -280,7 +280,7 @@ ആഴ്ചകൾ അനധികൃത അയക്കുക സ്വീകരിക്കുന്ന വിലാസം മാറണോ\? - കര്‍ത്തവ്യം \"%s\" ആയി മാറ്റും. അംഗത്തിന് പുതിയ ക്ഷണം ലഭിക്കും. + കര്‍ത്തവ്യം "%s" ആയി മാറ്റും. അംഗത്തിന് പുതിയ ക്ഷണം ലഭിക്കും. സംവിധാനം പ്രാമാണീകരണം അംഗങ്ങളെ ക്ഷണിക്കുന്നത് ഒഴിവാക്കുക സ്വാഗത സന്ദേശം സംരക്ഷിക്കണോ\? diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml index 97b6586844..9a8810de84 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml @@ -767,7 +767,7 @@ %1$s LEDEN U kunt een link of een QR-code delen. Iedereen kan lid worden van de groep. U verliest geen leden van de groep als u deze later verwijdert. Wijzig - De rol wordt gewijzigd in \"%s\". Iedereen in de groep wordt op de hoogte gebracht. + De rol wordt gewijzigd in "%s". Iedereen in de groep wordt op de hoogte gebracht. Ontvang via Groep profiel opslaan Volledig gedecentraliseerd – alleen zichtbaar voor leden. @@ -800,7 +800,7 @@ Lid verwijderen Rol Direct bericht sturen - De rol wordt gewijzigd in \"%s\". De gebruiker ontvangt een nieuwe uitnodiging. + De rol wordt gewijzigd in "%s". De gebruiker ontvangt een nieuwe uitnodiging. Verzenden via SERVERS Resetten naar standaardwaarden @@ -973,7 +973,7 @@ Profiel privé maken! Nu kunnen beheerders: \n- berichten van leden verwijderen. -\n- schakel leden uit (\"waarnemer\" rol) +\n- schakel leden uit ("waarnemer" rol) Bescherm je chat profielen met een wachtwoord! Wachtwoord om weer te geven Groep profiel opslaan en bijwerken diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml index d0b0ca0d1c..62ff44f6db 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml @@ -739,7 +739,7 @@ Przełącz Zmień adres odbioru W pełni zdecentralizowana – widoczna tylko dla członków. - Rola zostanie zmieniona na \"%s\". Członek otrzyma nowe zaproszenie. + Rola zostanie zmieniona na "%s". Członek otrzyma nowe zaproszenie. Wiadomość powitalna Usunąć profil czatu\? Usuń profil czatu dla @@ -944,7 +944,7 @@ Nie udało się załadować czatu Teraz administratorzy mogą: \n- usuwać wiadomości członków. -\n- wyłączyć członków (rola \"obserwatora\") +\n- wyłączyć członków (rola "obserwatora") Z Galerii Obraz Wideo @@ -993,7 +993,7 @@ Niektóre serwery nie przeszły testu: Dziękujemy za zainstalowanie SimpleX Chat! Wiadomość zostanie oznaczona jako zmoderowana dla wszystkich członków. - Rola zostanie zmieniona na \"%s\". Wszyscy w grupie zostaną powiadomieni. + Rola zostanie zmieniona na "%s". Wszyscy w grupie zostaną powiadomieni. Tego działania nie można cofnąć - wszystkie odebrane i wysłane pliki oraz media zostaną usunięte. Obrazy o niskiej rozdzielczości pozostaną. Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online. Ten link nie jest prawidłowym linkiem połączenia! diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml index 2fa9f85599..3c639cf777 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml @@ -695,14 +695,14 @@ não Agora administradores podem: \n- excluir mensagens de membros. -\n- desativar membros (cargo de \"observador\") +\n- desativar membros (cargo de "observador") Moderação do grupo Mensagem de boas-vindas do grupo Desatualizar banco de dados migração diferente no aplicativo/banco de dados: %s / %s Convidar para o grupo Sem contatos para adicionar - O cargo será alterada para \"%s\". Todos no grupo serão notificados. + O cargo será alterada para "%s". Todos no grupo serão notificados. Mutar Somente você pode enviar mensagens de voz. Somente seu contato pode enviar mensagens de voz. @@ -813,7 +813,7 @@ EXPERIMENTAL você alterou o endereço Atualização do banco de dados - O cargo será alterado para \"%s\". O membro receberá um novo convite. + O cargo será alterado para "%s". O membro receberá um novo convite. Somente os proprietários do grupo podem alterar as preferências do grupo. Adicionar mensagem de boas-vindas Mensagem de boas-vindas diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml index e652ab27e5..b38348b30f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml @@ -631,7 +631,7 @@ ligado Agora os administradores podem: \n- eliminar mensagens de membros. -\n- desativar membros (função de \"observador\") +\n- desativar membros (função de "observador") Ligação do grupo SimpleX Apenas 10 imagens podem ser enviadas ao mesmo tempo Apenas 10 vídeos podem ser enviados ao mesmo tempo diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml index 8c5adae3e3..2e9725913a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -796,8 +796,8 @@ Поменять Переключить Поменять роль в группе? - Роль будет изменена на \"%s\". Все в группе получат сообщение. - Роль будет изменена на \"%s\". Будет отправлено новое приглашение. + Роль будет изменена на "%s". Все в группе получат сообщение. + Роль будет изменена на "%s". Будет отправлено новое приглашение. Ошибка при удалении члена группы Ошибка при изменении роли Группа @@ -964,7 +964,7 @@ Исчезающие сообщения Отправленные сообщения будут удалены через заданное время. Улучшенная конфигурация серверов - \"Живые\" сообщения + "Живые" сообщения Получатели видят их в то время как Вы их набираете. Проверить безопасность соединения Сравните код безопасности с Вашими контактами. @@ -1065,7 +1065,7 @@ Дополнительные улучшения скоро! Теперь админы могут: \n- удалять сообщения членов. -\n- приостанавливать членов (роль \"наблюдатель\") +\n- приостанавливать членов (роль "наблюдатель") Защитите Ваши профили чата паролем! Раскрыть Поддержка bluetooth и другие улучшения. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml index 058f0305a8..03bf9f0f27 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml @@ -742,7 +742,7 @@ การปรับปรุงเพิ่มเติมกำลังจะมาเร็ว ๆ นี้! ขณะนี้ผู้ดูแลระบบสามารถ: \n- ลบข้อความของสมาชิก -\n- ปิดการใช้งานสมาชิก (บทบาท \"ผู้สังเกตการณ์\") +\n- ปิดการใช้งานสมาชิก (บทบาท "ผู้สังเกตการณ์") ปฏิกิริยาต่อข้อความ นาที เดือน @@ -1020,7 +1020,7 @@ ขอบคุณผู้ใช้ – มีส่วนร่วมผ่าน Weblate! แพลตฟอร์มการส่งข้อความและแอปพลิเคชันที่ปกป้องความเป็นส่วนตัวและความปลอดภัยของคุณ การส่งข้อความส่วนตัวรุ่นต่อไป - บทบาทจะถูกเปลี่ยนเป็น \"%s\" ทุกคนในกลุ่มจะได้รับแจ้ง + บทบาทจะถูกเปลี่ยนเป็น "%s" ทุกคนในกลุ่มจะได้รับแจ้ง การดำเนินการนี้ไม่สามารถยกเลิกได้ ไฟล์และสื่อที่ได้รับและส่งทั้งหมดจะถูกลบ รูปภาพความละเอียดต่ำจะยังคงอยู่ หากต้องการเปิดเผยโปรไฟล์ที่ซ่อนอยู่ของคุณ ให้ป้อนรหัสผ่านแบบเต็มในช่องค้นหาในหน้าโปรไฟล์แชทของคุณ การแยกการขนส่ง @@ -1198,7 +1198,7 @@ ข้อความต้อนรับ คุณสามารถแชร์ลิงก์หรือคิวอาร์โค้ดได้ ทุกคนจะสามารถเข้าร่วมกลุ่มได้ คุณจะไม่สูญเสียสมาชิกของกลุ่มหากคุณลบในภายหลัง คุณสามารถแบ่งปันที่อยู่นี้กับผู้ติดต่อของคุณเพื่อให้พวกเขาเชื่อมต่อกับ %s - บทบาทจะถูกเปลี่ยนเป็น \"%s\" สมาชิกจะได้รับคำเชิญใหม่ + บทบาทจะถูกเปลี่ยนเป็น "%s" สมาชิกจะได้รับคำเชิญใหม่ ข้อความต้อนรับ โปรไฟล์การแชทของคุณจะถูกส่งไปยังสมาชิกในกลุ่ม อัปเดต diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml index 5413afa82b..864b5ae3df 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml @@ -138,14 +138,14 @@ Kaydet ve kişiyi bilgilendir Parolayı, Keystore\'a kaydet. Ses açık - Yetki, \"%s\" olarak değiştirelecek. Gruptaki herkes bilgilendirilecek. + Yetki, "%s" olarak değiştirelecek. Gruptaki herkes bilgilendirilecek. Sesli/görüntülü aramalar yasaktır. Kimlik doğrulama başarısız SimpleX Adresi Mesaj, tüm üyeler için silinecek. Gizliliğinizi ve güvenliğinizi koruyan mesajlaşma ve uygulama platformu. Gizlilik kipi - Yetki, \"%s\" olarak değiştirilecek. Üye, yeni bir davet alacak. + Yetki, "%s" olarak değiştirilecek. Üye, yeni bir davet alacak. Yetki Sesli mesajlara izin verilsin mi? Profil ekle @@ -360,7 +360,7 @@ %d saat Yeni yöneticiler artık: \n- üyelerin mesajlarını silebilir. -\n- üyeleri etkisizleştirebilir (\"gözlemci\" yetkisi verir) +\n- üyeleri etkisizleştirebilir ("gözlemci" yetkisi verir) Konuşmalar Grup bağlantısı oluştur Konuşma isteğini onaylarken hata oluştu diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml index ee77905611..f6b3b12431 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml @@ -726,8 +726,8 @@ Зникає о: %s (поточне) Вилучити учасника - Роль буде змінено на \"%s\". Всі учасники групи будуть сповіщені. - Роль буде змінено на \"%s\". Учасник отримає нове запрошення. + Роль буде змінено на "%s". Всі учасники групи будуть сповіщені. + Роль буде змінено на "%s". Учасник отримає нове запрошення. Група Ласкаво просимо Профіль групи зберігається на пристроях учасників, а не на серверах. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml index 9e038995b3..469ce9b5b1 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml @@ -1327,7 +1327,7 @@ 启用 该群组成员超过 %1$d ,未发送送达回执。 修复连接? - 我们错过的第二个\"√\"!✅ + 我们错过的第二个"√"!✅ 设定数据库密码 为群组禁用回执吗? %s、%s 和 %s 已连接 diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml index 48efa52563..17cc45334e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml @@ -599,8 +599,8 @@ 建立連結 刪除連結? 移除成員 - 成員的身份會修改為 \"%s\"。所有在群組內的成員都接收到通知。 - 成員的身份會修改為 \"%s\"。該成員將接收到新的邀請。 + 成員的身份會修改為 "%s"。所有在群組內的成員都接收到通知。 + 成員的身份會修改為 "%s"。該成員將接收到新的邀請。 網路狀態 重置為預設值 當你與某人分享已啟用匿名聊天模式的個人檔案時,此個人檔案將用於他們邀請你參加的群組。 From 9cba96082d346d31c6e57713df928c918db97b4c Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:37:04 +0000 Subject: [PATCH 18/19] android, desktop: fix crash when window is small in chat view (#4819) --- .../kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt index 8921685cd6..2941b748c7 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt @@ -356,7 +356,8 @@ sealed class WallpaperType { private fun drawToBitmap(image: ImageBitmap, imageScale: Float, tint: Color, size: Size, density: Float, layoutDirection: LayoutDirection): ImageBitmap { val quality = if (appPlatform.isAndroid) FilterQuality.High else FilterQuality.Low val drawScope = CanvasDrawScope() - val bitmap = ImageBitmap(size.width.toInt(), size.height.toInt()) + // Don't allow to make zero size because it crashes the app when reducing a size of a window on desktop + val bitmap = ImageBitmap(size.width.toInt().coerceAtLeast(1), size.height.toInt().coerceAtLeast(1)) val canvas = Canvas(bitmap) drawScope.draw( density = Density(density), From 6407d5de638a25bff6beb121038c7dfdc2394dd3 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:38:42 +0000 Subject: [PATCH 19/19] android, desktop: making list items unique (#4812) --- .../commonMain/kotlin/chat/simplex/common/model/ChatModel.kt | 4 +++- .../commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt | 1 + .../kotlin/chat/simplex/common/views/TerminalView.kt | 2 +- .../kotlin/chat/simplex/common/views/chat/ChatView.kt | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index 5a1c46666d..618ad8f4b8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt @@ -411,7 +411,9 @@ object ChatModel { // remove from current chat if (chatId.value == cInfo.id) { chatItems.removeAll { - val remove = it.id == cItem.id + // We delete taking into account meta.createdAt to make sure we will not be in situation when two items with the same id will be deleted + // (it can happen if already deleted chat item in backend still in the list and new one came with the same (re-used) chat item id) + val remove = it.id == cItem.id && it.meta.createdAt == cItem.meta.createdAt if (remove) { AudioPlayer.stop(it) } remove } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 983390b09e..4d5caea16a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -5316,6 +5316,7 @@ abstract class TerminalItem { val date: Instant = Clock.System.now() abstract val label: String abstract val details: String + val createdAtNanos: Long = System.nanoTime() class Cmd(override val id: Long, override val remoteHostId: Long?, val cmd: CC): TerminalItem() { override val label get() = "> ${cmd.cmdString}" diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt index 1afbb0bdcb..5cb97d7d80 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt @@ -132,7 +132,7 @@ fun TerminalLog() { } val clipboard = LocalClipboardManager.current LazyColumnWithScrollBar(reverseLayout = true) { - items(reversedTerminalItems) { item -> + items(reversedTerminalItems, key = { item -> item.id to item.createdAtNanos }) { item -> val rhId = item.remoteHostId val rhIdStr = if (rhId == null) "" else "$rhId " Text( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index c8ad89609d..92c023c518 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -998,7 +998,7 @@ fun BoxWithConstraintsScope.ChatItemsList( } ) LazyColumnWithScrollBar(Modifier.align(Alignment.BottomCenter), state = listState, reverseLayout = true) { - itemsIndexed(reversedChatItems, key = { _, item -> item.id }) { i, cItem -> + itemsIndexed(reversedChatItems, key = { _, item -> item.id to item.meta.createdAt.toEpochMilliseconds() }) { i, cItem -> CompositionLocalProvider( // Makes horizontal and vertical scrolling to coexist nicely. // With default touchSlop when you scroll LazyColumn, you can unintentionally open reply view