From d492606f01a24c242beef2249c5e3ca5b6f83650 Mon Sep 17 00:00:00 2001 From: sh <37271604+shumvgolove@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:15:53 +0400 Subject: [PATCH 1/7] scripts: match AGP zip alignment in android reproduce build (#7196) Release APKs are packaged by AGP (:android:assembleRelease), which zero-pads ZIP alignment. verify_apk re-aligned the rebuilt APK with repro-apk's --pad-like-apksigner (the 0xd935 extra-field scheme of standalone apksigner >= 35.0.0-rc1), so apksigcopier aborted with "APK Signing Block offset < central directory offset". Drop the flag so the padding matches AGP's output; the rebuilt APK then reproduces the published one byte-for-byte. --- scripts/simplex-chat-reproduce-builds-android.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/simplex-chat-reproduce-builds-android.sh b/scripts/simplex-chat-reproduce-builds-android.sh index 20c2fdf116..f8bb3224cc 100755 --- a/scripts/simplex-chat-reproduce-builds-android.sh +++ b/scripts/simplex-chat-reproduce-builds-android.sh @@ -118,9 +118,14 @@ check_apk() { verify_apk() { apk_name="$1" + # Release APKs are packaged by AGP (gradle :android:assembleRelease; AGP version is + # gradle.plugin.version in apps/multiplatform/gradle.properties), which zero-pads ZIP + # alignment. Do NOT add --pad-like-apksigner (standalone apksigner >= 35.0.0-rc1 uses + # the 0xd935 extra-field padding) unless AGP is bumped to a packager that uses it — + # otherwise apksigcopier aborts with "APK Signing Block offset < central directory offset". # https://github.com/obfusk/apksigcopier?tab=readme-ov-file#what-about-signatures-made-by-apksigner-from-build-tools--3500-rc1 - docker exec "${CONTAINER_NAME}" repro-apk zipalign --page-size 16 --pad-like-apksigner --replace "${DOCKER_PATH_VERIFY}/${apk_name}.${SUFFIX_BUILT}" \ - "${DOCKER_PATH_VERIFY}/${apk_name}.aligned" + docker exec "${CONTAINER_NAME}" repro-apk zipalign --page-size 16 --replace "${DOCKER_PATH_VERIFY}/${apk_name}.${SUFFIX_BUILT}" \ + "${DOCKER_PATH_VERIFY}/${apk_name}.aligned" docker exec "${CONTAINER_NAME}" mv "${DOCKER_PATH_VERIFY}/${apk_name}.aligned" \ "${DOCKER_PATH_VERIFY}/${apk_name}.${SUFFIX_BUILT}" From a58cd51c491b9aa639095c4b6dd47f783d66bbee Mon Sep 17 00:00:00 2001 From: sh <37271604+shumvgolove@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:26:04 +0400 Subject: [PATCH 2/7] ui: translations (#7317) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (German) Currently translated at 100.0% (2899 of 2899 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (Russian) Currently translated at 97.5% (2829 of 2899 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/ * Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 99.9% (2898 of 2899 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (Spanish) Currently translated at 100.0% (2899 of 2899 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (2497 of 2497 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/ * ru translations * Translated using Weblate (German) Currently translated at 100.0% (2899 of 2899 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (Russian) Currently translated at 97.5% (2829 of 2899 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/ * Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 99.9% (2898 of 2899 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (Spanish) Currently translated at 100.0% (2899 of 2899 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (2497 of 2497 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/ * process translations * ui: fix translation errors in es, ru, de, it, hu Review of the translations in this PR against the English originals. Values only - no keys added, removed or renamed. Spanish: - "The sender deleted the connection request." said "El servidor..." (the server), attributing the deletion to a server rather than the sender. Restored "El remitente". - "Require/Do not require signing messages." were rendered as statements ("Se requieren mensajes firmados."), making the toggle options read identically to the separate status strings "Message signing is (not) required.". Restored the imperative. - "...compare (or scan) the code on your devices." said "en tu dispositivo" (singular); the code has to be compared on both. - "How to register a test name" was pluralised to "nombres en pruebas". Russian: - "Помошь и поддержка" -> "Помощь и поддержка" (spelling). - "File servers" was the calque "Файл серверы" -> "Серверы файлов", matching the iOS translation of the same string. - "Если Вы выберите" -> "выберете" (imperative used for future). - "Create web preview." said "Создать веб страницу." (web page, also missing the hyphen) -> "Создать веб-предпросмотр.". - webpage_info dropped "to show your channel preview to visitors before they subscribe"; webpage_url_footer said "страницы канала" instead of the preview. Both restored from the iOS wording. - "Enter description (optional)" lost "(optional)"; "Error adding relays" was truncated to "Ошибка добавления". - "Add contributors." used "авторов"; the member role is "соавтор". - "удален(а)" -> "удалён", "подтвержденный" -> "подтверждённый". German, Italian, Hungarian: - The source strings "Names for your channel or business." and "SimpleX names (BETA)" were renamed to "Public names..." and "SimpleX public names (BETA)", but the old values were carried over, so "public" was missing. Android German and Chinese had already been updated in this PR; this brings iOS German, and both platforms for Italian and Hungarian, in line. - iOS German "How to register a test name" still read "Einen Test-Namen registrieren", while Android German was updated in this PR. --------- Co-authored-by: mlanp Co-authored-by: Evgeny Poberezkin Co-authored-by: Hosted Weblate user 54392 Co-authored-by: No name Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com> Co-authored-by: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> --- .../bg.xcloc/Localized Contents/bg.xliff | 16 +- .../cs.xcloc/Localized Contents/cs.xliff | 16 +- .../de.xcloc/Localized Contents/de.xliff | 22 +- .../en.xcloc/Localized Contents/en.xliff | 20 +- .../es.xcloc/Localized Contents/es.xliff | 48 ++- .../fi.xcloc/Localized Contents/fi.xliff | 16 +- .../fr.xcloc/Localized Contents/fr.xliff | 16 +- .../hu.xcloc/Localized Contents/hu.xliff | 20 +- .../it.xcloc/Localized Contents/it.xliff | 20 +- .../ja.xcloc/Localized Contents/ja.xliff | 16 +- .../nl.xcloc/Localized Contents/nl.xliff | 16 +- .../pl.xcloc/Localized Contents/pl.xliff | 16 +- .../ru.xcloc/Localized Contents/ru.xliff | 135 ++++++- .../th.xcloc/Localized Contents/th.xliff | 16 +- .../tr.xcloc/Localized Contents/tr.xliff | 16 +- .../uk.xcloc/Localized Contents/uk.xliff | 16 +- .../Localized Contents/zh-Hans.xliff | 16 +- .../SimpleX SE/ru.lproj/Localizable.strings | 3 + apps/ios/de.lproj/Localizable.strings | 14 +- apps/ios/es.lproj/Localizable.strings | 97 +++++ apps/ios/hu.lproj/Localizable.strings | 12 +- apps/ios/it.lproj/Localizable.strings | 12 +- apps/ios/ru.lproj/Localizable.strings | 345 +++++++++++++++++- .../commonMain/resources/MR/de/strings.xml | 6 +- .../commonMain/resources/MR/es/strings.xml | 23 +- .../commonMain/resources/MR/hu/strings.xml | 4 +- .../commonMain/resources/MR/it/strings.xml | 4 +- .../commonMain/resources/MR/ru/strings.xml | 93 ++++- .../resources/MR/zh-rCN/strings.xml | 6 +- 29 files changed, 874 insertions(+), 186 deletions(-) diff --git a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff index b45b74020b..0b7e24f040 100644 --- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff +++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff @@ -5702,10 +5702,6 @@ This is your link for group %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Мрежа и сървъри @@ -6826,6 +6822,10 @@ Enable in *Network & servers* settings. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications Push известия @@ -8275,10 +8275,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation Еднократна покана за SimpleX @@ -8288,6 +8284,10 @@ copied message info SimpleX protocols reviewed by Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff index ffe28137a1..0549fdc20b 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -5517,10 +5517,6 @@ This is your link for group %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Síť a servery @@ -6619,6 +6615,10 @@ Enable in *Network & servers* settings. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications Nabízená oznámení @@ -8044,10 +8044,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation Jednorázová pozvánka SimpleX @@ -8057,6 +8053,10 @@ copied message info SimpleX protocols reviewed by Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff index 5471823002..6fd8232e93 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -4927,7 +4927,7 @@ Fehler: %2$@ How to register a test name - Einen Test-Namen registrieren + Wie man einen Test-Namen registriert No comment provided by engineer. @@ -6062,11 +6062,6 @@ Das ist Ihr Link für die Gruppe %@! Name wurde nicht gefunden No comment provided by engineer. - - Public names for your channel or business. - Namen für Ihren Kanal oder Ihr Unternehmen. - No comment provided by engineer. - Network & servers Netzwerk und Server @@ -7322,6 +7317,11 @@ Aktivieren Sie es in den *Netzwerk und Server* Einstellungen. Öffentliche Kanäle – frei sprechen 🚀 No comment provided by engineer. + + Public names for your channel or business. + Öffentliche Namen für Ihren Kanal oder Ihr Unternehmen. + No comment provided by engineer. + Push notifications Push-Benachrichtigungen @@ -8933,11 +8933,6 @@ copied message info SimpleX-Name ist nicht verifiziert alert title - - SimpleX public names (BETA) - SimpleX-Namen (BETA) - No comment provided by engineer. - SimpleX one-time invitation SimpleX-Einmal-Einladung @@ -8948,6 +8943,11 @@ copied message info Die SimpleX-Protokolle wurden von Trail of Bits überprüft. No comment provided by engineer. + + SimpleX public names (BETA) + Öffentliche SimpleX-Namen (BETA) + No comment provided by engineer. + SimpleX relay address SimpleX Relais-Adresse diff --git a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff index d144cb156d..97a8d4879c 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -6062,11 +6062,6 @@ This is your link for group %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - Public names for your channel or business. - No comment provided by engineer. - Network & servers Network & servers @@ -7322,6 +7317,11 @@ Enable in *Network & servers* settings. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + Public names for your channel or business. + No comment provided by engineer. + Push notifications Push notifications @@ -8933,11 +8933,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation SimpleX one-time invitation @@ -8948,6 +8943,11 @@ copied message info SimpleX protocols reviewed by Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address SimpleX relay address diff --git a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff index ba52899df8..6d140c7f78 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -773,10 +773,12 @@ swipe action Add contributors. + Añade colaboradores. No comment provided by engineer. Add description + Añadir descripción No comment provided by engineer. @@ -1453,6 +1455,7 @@ en tu red Better channels 📢 + Canales mejorados 📢 No comment provided by engineer. @@ -1800,6 +1803,7 @@ set passcode view Channel SimpleX name + Nombre SimpleX del canal No comment provided by engineer. @@ -2658,6 +2662,7 @@ This is your own one-time link! Create web preview. + Crea previsualizaciones web. No comment provided by engineer. @@ -3377,6 +3382,7 @@ alert button Do not require signing messages. + No requerir la firma de mensajes. No comment provided by engineer. @@ -3416,6 +3422,7 @@ alert button Don't save + No guardar alert action @@ -3501,6 +3508,7 @@ chat item action Easier to read. + Fácil de leer. No comment provided by engineer. @@ -3515,6 +3523,7 @@ chat item action Edit description + Editar descripción No comment provided by engineer. @@ -3719,6 +3728,7 @@ chat item action Enter description (optional) + Introduce descripción (opcional) placeholder @@ -4148,6 +4158,7 @@ chat item action Error sharing address + Error compartiendo dirección alert title @@ -4375,10 +4386,12 @@ server test error File servers + Servidores de archivos No comment provided by engineer. File servers: %@ + Servidores de archivos: %@ copied message info @@ -4684,6 +4697,7 @@ Error: %2$@ Get SimpleX name (BETA) + Obtener nombre SimpleX (BETA) No comment provided by engineer. @@ -4913,6 +4927,7 @@ Error: %2$@ How to register a test name + Cómo registrar un nombre de prueba No comment provided by engineer. @@ -5599,6 +5614,7 @@ This is your link for group %@! Manage your relays. + Gestiona tus servidores. No comment provided by engineer. @@ -5818,10 +5834,12 @@ This is your link for group %@! Message signing is not required. + Los mensajes firmados no son obligatorios. No comment provided by engineer. Message signing is required. + Los mensajes firmados son obligatorios. No comment provided by engineer. @@ -6044,10 +6062,6 @@ This is your link for group %@! Nombre no encontrado No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Servidores y Redes @@ -7303,6 +7317,11 @@ Actívalo en ajustes de *Servidores y Redes*. Canales públicos - habla con libertad 🚀 No comment provided by engineer. + + Public names for your channel or business. + Nombres públicos para tu canal o negocio. + No comment provided by engineer. + Push notifications Notificaciones push @@ -7602,6 +7621,7 @@ swipe action Remove name + Eliminar nombre No comment provided by engineer. @@ -7721,6 +7741,7 @@ swipe action Require signing messages. + Requerir la firma de mensajes. No comment provided by engineer. @@ -7927,6 +7948,7 @@ chat item action Save SimpleX name? + ¿Guardar el nombre SimpleX? alert title @@ -8737,6 +8759,7 @@ chat item action Show encryption + Mostrar cifrado No comment provided by engineer. @@ -8771,27 +8794,33 @@ chat item action Sign message + Firmar mensaje No comment provided by engineer. Sign messages + Firmar mensajes chat feature Signature missing + Falta la firma alert title copied message info Signed + Firmado copied message info Signed & verified + Firmado y verificado copied message info Signing proves you authored this message and can't be denied later. + La firma prueba que eres el autor del mensaje sin posibilidad de repudio. No comment provided by engineer. @@ -8904,10 +8933,6 @@ copied message info Nombre SimpleX no verificado alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation Invitación SimpleX de un uso @@ -8918,6 +8943,11 @@ copied message info Protocolos de SimpleX auditados por Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + Nombres públicos SimpleX (BETA) + No comment provided by engineer. + SimpleX relay address Dirección de servidor SimpleX @@ -9443,6 +9473,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. The channel required this message to be signed, but the signature is missing. + El canal requiere que el mensaje esté firmado, pero falta la firma. alert message @@ -9832,6 +9863,7 @@ Se te pedirá que completes la autenticación antes de activar esta función. To verify keys with this subscriber, compare (or scan) the code on your devices. + Para verificar las claves con este suscriptor, compara (o escanea) el código en ambos dispositivos. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff index ce331bceeb..cd6030b2be 100644 --- a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff +++ b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff @@ -5401,10 +5401,6 @@ This is your link for group %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Verkko ja palvelimet @@ -6499,6 +6495,10 @@ Enable in *Network & servers* settings. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications Push-ilmoitukset @@ -7923,10 +7923,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation SimpleX-kertakutsu @@ -7936,6 +7932,10 @@ copied message info SimpleX protocols reviewed by Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff index 622a16bc32..cf8eafaac6 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -6017,10 +6017,6 @@ Voici votre lien pour le groupe %@ ! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Réseau et serveurs @@ -7271,6 +7267,10 @@ Activez-le dans les paramètres *Réseau et serveurs*. Les canaux publics – parlez librement 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications Notifications push @@ -8857,10 +8857,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation Invitation unique SimpleX @@ -8871,6 +8867,10 @@ copied message info Protocoles SimpleX audité par Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address Adresse relais SimpleX diff --git a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff index 66646b0ad0..b3facbe03e 100644 --- a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff +++ b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff @@ -6062,11 +6062,6 @@ Ez a saját hivatkozása a(z) %@ nevű csoporthoz! Nem található a név No comment provided by engineer. - - Public names for your channel or business. - Nevek a csatornákhoz vagy az üzleti profilokhoz. - No comment provided by engineer. - Network & servers Hálózat és kiszolgálók @@ -7322,6 +7317,11 @@ Engedélyezze a *Hálózat és kiszolgálók* menüben. Nyilvános csatornák – mondja el szabadon a véleményét 🚀 No comment provided by engineer. + + Public names for your channel or business. + Nyilvános nevek a csatornákhoz vagy az üzleti profilokhoz. + No comment provided by engineer. + Push notifications Leküldéses értesítések @@ -8933,11 +8933,6 @@ copied message info Nincs ellenőrizve a SimpleX-név alert title - - SimpleX public names (BETA) - SimpleX-nevek (béta) - No comment provided by engineer. - SimpleX one-time invitation Egyszer használható SimpleX meghívó @@ -8948,6 +8943,11 @@ copied message info A SimpleX protokollokat a Trail of Bits auditálta. No comment provided by engineer. + + SimpleX public names (BETA) + Nyilvános SimpleX-nevek (béta) + No comment provided by engineer. + SimpleX relay address SimpleX-átjátszó címe diff --git a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff index f5534b76b0..5381b8cbb5 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -6062,11 +6062,6 @@ Questo è il tuo link per il gruppo %@! Nome non trovato No comment provided by engineer. - - Public names for your channel or business. - Nomi per il tuo canale o per il lavoro. - No comment provided by engineer. - Network & servers Rete e server @@ -7322,6 +7317,11 @@ Attivalo nelle impostazioni *Rete e server*. Canali pubblici - parla liberamente 🚀 No comment provided by engineer. + + Public names for your channel or business. + Nomi pubblici per il tuo canale o per il lavoro. + No comment provided by engineer. + Push notifications Notifiche push @@ -8933,11 +8933,6 @@ copied message info Nome SimpleX non verificato alert title - - SimpleX public names (BETA) - Nomi SimpleX (BETA) - No comment provided by engineer. - SimpleX one-time invitation Invito SimpleX una tantum @@ -8948,6 +8943,11 @@ copied message info Protocolli di SimpleX esaminati da Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + Nomi pubblici SimpleX (BETA) + No comment provided by engineer. + SimpleX relay address Indirizzo del relay SimpleX diff --git a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff index 936e35f3ae..c8b2285649 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -5519,10 +5519,6 @@ This is your link for group %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers ネットワークとサーバ @@ -6620,6 +6616,10 @@ Enable in *Network & servers* settings. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications プッシュ通知 @@ -8036,10 +8036,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation SimpleX使い捨て招待リンク @@ -8049,6 +8045,10 @@ copied message info SimpleX protocols reviewed by Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff index dbc0442594..11f81cf90b 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -5858,10 +5858,6 @@ Dit is jouw link voor groep %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Netwerk & servers @@ -7058,6 +7054,10 @@ Schakel dit in in *Netwerk en servers*-instellingen. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications Push meldingen @@ -8601,10 +8601,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation Eenmalige SimpleX uitnodiging @@ -8615,6 +8611,10 @@ copied message info SimpleX-protocollen beoordeeld door Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff index e46bd6caa2..19401459d5 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -5907,10 +5907,6 @@ To jest twój link do grupy %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Sieć i serwery @@ -7123,6 +7119,10 @@ Włącz w ustawianiach *Sieć i serwery* . Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications Powiadomienia push @@ -8687,10 +8687,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation Zaproszenie jednorazowe SimpleX @@ -8701,6 +8697,10 @@ copied message info Protokoły SimpleX sprawdzone przez Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff index 21ddb2553e..7254d80c9c 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -37,6 +37,7 @@ %1$@ supported SimpleX Chat. The badge expired on %2$@. + %1$@ поддерживал(а) SimpleX Chat. Срок действия значка истёк %2$@. badge alert @@ -91,6 +92,7 @@ %@ invested in SimpleX Chat crowdfunding. + %@ инвестировал(а) в краудфандинг SimpleX Chat. badge alert @@ -120,6 +122,7 @@ %@ supports SimpleX Chat. + %@ поддерживает SimpleX Chat. badge alert @@ -199,6 +202,7 @@ %d owner + %d владелец channel owners count @@ -769,10 +773,12 @@ swipe action Add contributors. + Добавить соавторов. No comment provided by engineer. Add description + Добавить описание No comment provided by engineer. @@ -802,10 +808,12 @@ swipe action Add relays + Добавить релеи No comment provided by engineer. Add relays to restore message delivery. + Добавить релеи для восстановления доставки сообщений. No comment provided by engineer. @@ -825,6 +833,7 @@ swipe action Add this code to your webpage. It will display the preview of your channel / group. + Добавьте этот код на свой веб-сайт. Он отобразит предпросмотр вашего канала или группы. No comment provided by engineer. @@ -909,6 +918,7 @@ swipe action Advanced options + Продвинутые настройки No comment provided by engineer. @@ -1023,6 +1033,7 @@ swipe action Allow anyone to embed + Разрешить всем встраивать No comment provided by engineer. @@ -1202,6 +1213,7 @@ swipe action Any webpage can show the preview. + Предпросмотр можно отобразить на любой веб-странице. No comment provided by engineer. @@ -1246,6 +1258,7 @@ swipe action App update required + Необходимо обновление приложения alert title @@ -1415,6 +1428,7 @@ swipe action Badge cannot be verified + Не удалось проверить подлинность значка badge alert title @@ -1441,6 +1455,7 @@ in your network Better channels 📢 + Улучшенные каналы 📢 No comment provided by engineer. @@ -1682,10 +1697,12 @@ new chat action Cancel and delete channel + Отменить и удалить канал No comment provided by engineer. Cancel creating channel? + Отменить создание канала? alert title @@ -1765,6 +1782,7 @@ new chat action Change role? + Изменить роль? No comment provided by engineer. @@ -1785,6 +1803,7 @@ set passcode view Channel SimpleX name + SimpleX имя канала No comment provided by engineer. @@ -1840,6 +1859,7 @@ alert subtitle Channel webpage + Веб-страница канала No comment provided by engineer. @@ -1854,6 +1874,7 @@ alert subtitle Channel will start working with %1$d of %2$d relays. Continue? + Канал начнёт работу с %1$d из %2$d релеев. Продолжить? alert message @@ -1888,6 +1909,7 @@ alert subtitle Chat data + Данные чата No comment provided by engineer. @@ -2269,6 +2291,7 @@ server test step Connect to %@ + Соединиться с %@ new chat action @@ -2382,6 +2405,7 @@ This is your own one-time link! Connection blocked: %@ + Соединение заблокировано: %@ conn error description @@ -2548,6 +2572,7 @@ This is your own one-time link! Copy code + Скопировать код No comment provided by engineer. @@ -2587,6 +2612,7 @@ This is your own one-time link! Create a webpage to show your channel preview to visitors before they subscribe. Host it yourself or use any static hosting. + Создайте веб-страницу, чтобы показывать предпросмотр Вашего канала посетителям до подписки. Хостите её сами или используйте любой статический хостинг. No comment provided by engineer. @@ -2636,6 +2662,7 @@ This is your own one-time link! Create web preview. + Создать веб-предпросмотр. No comment provided by engineer. @@ -2984,6 +3011,7 @@ swipe action Delete from history + Удалить из истории No comment provided by engineer. @@ -3354,6 +3382,7 @@ alert button Do not require signing messages. + Не требовать подпись сообщений. No comment provided by engineer. @@ -3393,6 +3422,7 @@ alert button Don't save + Не сохранять alert action @@ -3478,6 +3508,7 @@ chat item action Easier to read. + Легче для чтения. No comment provided by engineer. @@ -3492,6 +3523,7 @@ chat item action Edit description + Редактировать описание No comment provided by engineer. @@ -3696,6 +3728,7 @@ chat item action Enter description (optional) + Введите описание (необязательно) placeholder @@ -3740,6 +3773,7 @@ chat item action Enter webpage URL + Введите адрес страницы No comment provided by engineer. @@ -3794,6 +3828,7 @@ chat item action Error adding relays + Ошибка добавления релеев alert title @@ -3928,6 +3963,7 @@ chat item action Error deleting message + Ошибка удаления сообщения alert title @@ -4062,6 +4098,7 @@ chat item action Error saving name + Ошибка сохранения имени alert title @@ -4121,6 +4158,7 @@ chat item action Error sharing address + Ошибка отправки адреса alert title @@ -4348,10 +4386,12 @@ server test error File servers + Серверы файлов No comment provided by engineer. File servers: %@ + Серверы файлов: %@ copied message info @@ -4657,6 +4697,7 @@ Error: %2$@ Get SimpleX name (BETA) + Зарегистрировать SimpleX имя (BETA) No comment provided by engineer. @@ -4771,6 +4812,7 @@ Error: %2$@ Group webpage + Веб-страница группы No comment provided by engineer. @@ -4800,6 +4842,7 @@ Error: %2$@ Help & support + Помощь и поддержка No comment provided by engineer. @@ -4884,6 +4927,7 @@ Error: %2$@ How to register a test name + Как зарегистрировать тестовое имя No comment provided by engineer. @@ -5292,6 +5336,7 @@ More improvements are coming soon! It will be shown to subscribers and used to allow loading the preview. + Адрес будет показан подписчикам и разрешит загрузку предпросмотра. No comment provided by engineer. @@ -5311,7 +5356,7 @@ More improvements are coming soon! Join as %@ - Вступить как %s + Вступить как %@ No comment provided by engineer. @@ -5321,6 +5366,7 @@ More improvements are coming soon! Join channel %@ + Вступить в канал %@ new chat action @@ -5447,10 +5493,12 @@ This is your link for group %@! Let people connect to you via name registered with your SimpleX address. + Позвольте людям соединяться с Вами через имя, зарегистрированное для Вашего SimpleX адреса. No comment provided by engineer. Let people join via name registered with this channel link. + Позвольте людям вступать через имя, зарегистрированное для ссылки этого канала. No comment provided by engineer. @@ -5565,6 +5613,7 @@ This is your link for group %@! Manage your relays. + Управлять своими релеями. No comment provided by engineer. @@ -5784,10 +5833,12 @@ This is your link for group %@! Message signing is not required. + Подпись сообщений не обязательна. No comment provided by engineer. Message signing is required. + Подпись сообщений обязательна. No comment provided by engineer. @@ -5962,6 +6013,7 @@ This is your link for group %@! More privacy + Больше конфиденциальности No comment provided by engineer. @@ -6006,10 +6058,7 @@ This is your link for group %@! Name not found - No comment provided by engineer. - - - Public names for your channel or business. + Имя не найдено No comment provided by engineer. @@ -6198,6 +6247,7 @@ The most secure encryption. No available relays + Нет доступных релеев No comment provided by engineer. @@ -6327,6 +6377,7 @@ The most secure encryption. No relays + Релеи отсутствуют No comment provided by engineer. @@ -6346,6 +6397,7 @@ The most secure encryption. No servers to resolve names. + Нет серверов для разрешения имён. servers warning @@ -6365,6 +6417,7 @@ The most secure encryption. No valid link + Нет действительной ссылки No comment provided by engineer. @@ -6379,6 +6432,7 @@ The most secure encryption. None of your servers are set to resolve SimpleX names. Configure servers, or use a connection link. + Ни один из Ваших серверов не настроен для разрешения SimpleX имён. Настройте серверы или используйте ссылку для соединения. No comment provided by engineer. @@ -6608,6 +6662,7 @@ Requires compatible VPN. Only your page above can show the preview. + Предпросмотр можно отобразить только на Вашей странице, указанной выше. No comment provided by engineer. @@ -6801,6 +6856,7 @@ alert button Owners & contributors + Владельцы и соавторы No comment provided by engineer. @@ -7260,6 +7316,11 @@ Enable in *Network & servers* settings. Публичные каналы - говорите свободно 🚀 No comment provided by engineer. + + Public names for your channel or business. + Публичные имена для Вашего канала или бизнеса. + No comment provided by engineer. + Push notifications Доставка уведомлений @@ -7509,10 +7570,12 @@ swipe action Relay will be removed from channel - this cannot be undone! + Релей будет удалён из канала - это нельзя отменить! alert message Relays added: %@. + Добавлены релеи: %@. alert message @@ -7557,6 +7620,7 @@ swipe action Remove name + Удалить имя No comment provided by engineer. @@ -7566,10 +7630,12 @@ swipe action Remove relay + Удалить релей No comment provided by engineer. Remove relay? + Удалить релей? alert title @@ -7674,6 +7740,7 @@ swipe action Require signing messages. + Требовать подпись сообщений. No comment provided by engineer. @@ -7723,6 +7790,7 @@ swipe action Resolver error: %@ + Ошибка разрешения имени: %@ No comment provided by engineer. @@ -7817,6 +7885,7 @@ swipe action Role will be changed to "%@". All subscribers will be notified. + Роль будет изменена на "%@". Все подписчики получат сообщение. No comment provided by engineer. @@ -7878,6 +7947,7 @@ chat item action Save SimpleX name? + Сохранить SimpleX имя? alert title @@ -7897,6 +7967,7 @@ chat item action Save and notify members + Сохранить и уведомить членов группы No comment provided by engineer. @@ -7971,6 +8042,7 @@ chat item action Save webpage settings? + Сохранить настройки веб-страницы? alert title @@ -8370,6 +8442,7 @@ chat item action Server %@ does not support name resolution. Configure servers, or use a connection link. + Сервер %@ не поддерживает разрешение имён. Настройте серверы или используйте ссылку для соединения. No comment provided by engineer. @@ -8685,6 +8758,7 @@ chat item action Show encryption + Показывать шифрование No comment provided by engineer. @@ -8719,27 +8793,33 @@ chat item action Sign message + Подписать сообщение No comment provided by engineer. Sign messages + Подпись сообщений chat feature Signature missing + Подпись отсутствует alert title copied message info Signed + Подписано copied message info Signed & verified + Подписано и проверено copied message info Signing proves you authored this message and can't be denied later. + Подпись доказывает, что Вы — автор этого сообщения, и это нельзя будет отрицать. No comment provided by engineer. @@ -8839,20 +8919,19 @@ copied message info SimpleX name + SimpleX имя No comment provided by engineer. SimpleX name error + Ошибка SimpleX имени No comment provided by engineer. SimpleX name not verified + SimpleX имя не проверено alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation SimpleX одноразовая ссылка @@ -8863,6 +8942,11 @@ copied message info Аудит SimpleX протоколов от Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + Публичные SimpleX имена (BETA) + No comment provided by engineer. + SimpleX relay address Адрес релея SimpleX @@ -8973,6 +9057,7 @@ report reason Status + Статус No comment provided by engineer. @@ -9134,6 +9219,7 @@ Relay address was used to set up this relay for the channel. Support the project + Поддержать проект No comment provided by engineer. @@ -9331,18 +9417,22 @@ It can happen because of some bug or when the connection is compromised. The SimpleX name #%@ is registered without channel link. Add channel link to the name via the registration page. + SimpleX имя #%@ зарегистрировано без ссылки канала. Добавьте ссылку канала к имени на странице регистрации. alert message The SimpleX name %@ is registered, but it has no valid link. + SimpleX имя %@ зарегистрировано, но не имеет действительной ссылки. No comment provided by engineer. The SimpleX name %@ is registered, but not added to profile. Please add it to your address or channel profile, if you are the owner. + SimpleX имя %@ зарегистрировано, но не добавлено в профиль. Пожалуйста, добавьте его в профиль Вашего адреса или канала, если Вы владелец. No comment provided by engineer. The SimpleX name @%@ is registered without SimpleX address. Add your SimpleX address to the name via the registration page. + SimpleX имя @%@ зарегистрировано без SimpleX адреса. Добавьте Ваш SimpleX адрес к имени на странице регистрации. alert message @@ -9377,10 +9467,12 @@ It can happen because of some bug or when the connection is compromised. The badge is signed with a key that this version of the app does not recognize. Update the app to verify this badge. + Этот значок подписан ключом, который неизвестен текущей версии приложения. Обновите приложение, чтобы проверить его подлинность. badge alert The channel required this message to be signed, but the signature is missing. + Канал требует подпись сообщений, но у этого сообщения подпись отсутствует. alert message @@ -9467,7 +9559,7 @@ your contacts and groups. The same conditions will apply to operator **%@**. - Те же условия будут действовать для оператора **%s**. + Те же условия будут действовать для оператора **%@**. No comment provided by engineer. @@ -9542,6 +9634,7 @@ your contacts and groups. This SimpleX name is not registered. Please check the name. + Это SimpleX имя не зарегистрировано. Пожалуйста, проверьте имя. No comment provided by engineer. @@ -9566,6 +9659,7 @@ your contacts and groups. This badge could not be verified and may not be genuine. + Не удалось проверить подлинность этого значка. Возможно, он не является подлинным. badge alert @@ -9600,6 +9694,7 @@ your contacts and groups. This group requires a newer version of the app. Please update the app to join. + Эта группа требует более новой версии приложения. Пожалуйста, обновите приложение, чтобы вступить. alert message alert subtitle @@ -9610,6 +9705,7 @@ alert subtitle This is the last active relay. Removing it will prevent message delivery to subscribers. + Это последний активный релей. После его удаления доставка сообщений подписчикам будет невозможна. alert message @@ -9726,6 +9822,7 @@ You will be prompted to complete authentication before this feature is enabled.< To resolve names + Для разрешения имён No comment provided by engineer. @@ -9765,6 +9862,7 @@ You will be prompted to complete authentication before this feature is enabled.< To verify keys with this subscriber, compare (or scan) the code on your devices. + Чтобы подтвердить ключи с этим подписчиком, сравните (или сканируйте) код на ваших устройствах. No comment provided by engineer. @@ -9859,6 +9957,7 @@ You will be prompted to complete authentication before this feature is enabled.< Unconfirmed name + Неподтверждённое имя No comment provided by engineer. @@ -9958,6 +10057,7 @@ You will be prompted to complete authentication before this feature is enabled.< Unverified badge + Неподтверждённый значок badge alert title @@ -10193,6 +10293,7 @@ alert title Used chat relays do not support webpages. + Используемые чат-релеи не поддерживают веб-страницы. No comment provided by engineer. @@ -10217,6 +10318,7 @@ alert title Verify SimpleX names + Проверять SimpleX имена No comment provided by engineer. @@ -10246,6 +10348,7 @@ alert title Verify name + Проверить имя No comment provided by engineer. @@ -10410,10 +10513,12 @@ alert title Webpage code + Код веб-страницы No comment provided by engineer. Webpage settings were changed. If you save, the updated settings will be sent to subscribers. + Настройки веб-страницы были изменены. Если Вы сохраните их, обновлённые настройки будут отправлены подписчикам. alert message @@ -10640,6 +10745,7 @@ Repeat join request? You can enable them later via app Your privacy settings. + Вы можете включить их позже в настройках Конфиденциальности. No comment provided by engineer. @@ -10704,6 +10810,7 @@ Repeat join request? You can support SimpleX starting from v7 of the app. + Вы можете поддержать SimpleX начиная с версии приложения v7. badge alert @@ -10899,6 +11006,7 @@ Repeat connection request? Your SimpleX name + Ваше SimpleX имя No comment provided by engineer. @@ -11001,6 +11109,8 @@ To connect, ask your contact to create a new link. Your new channel %1$@ is connected to %2$d of %3$d relays. If you cancel, the channel will be deleted - you can create it again. + Ваш новый канал %1$@ подключен к %2$d из %3$d релеев. +Если Вы отмените, канал будет удалён - Вы сможете создать его снова. alert message @@ -11127,6 +11237,7 @@ Relays can access channel messages. acknowledged roster + подтверждённый список No comment provided by engineer. @@ -11397,6 +11508,7 @@ marked deleted chat item preview text contributor + соавтор member role @@ -11607,6 +11719,7 @@ pref value https:// + https:// No comment provided by engineer. @@ -12053,6 +12166,7 @@ last received msg: %2$@ subscriber + подписчик member role @@ -12572,6 +12686,7 @@ last received msg: %2$@ You can allow sharing in Your privacy / SimpleX Lock settings. + Вы можете разрешить отправку в настройках Конфиденциальность / Блокировка SimpleX. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff index 0c95e9565b..20dec9b68d 100644 --- a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff +++ b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff @@ -5383,10 +5383,6 @@ This is your link for group %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers เครือข่ายและเซิร์ฟเวอร์ @@ -6478,6 +6474,10 @@ Enable in *Network & servers* settings. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications การแจ้งเตือนแบบทันที @@ -7895,10 +7895,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation คำเชิญ SimpleX แบบครั้งเดียว @@ -7908,6 +7904,10 @@ copied message info SimpleX protocols reviewed by Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff index 198951d2b5..00385e5312 100644 --- a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff +++ b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff @@ -5905,10 +5905,6 @@ Bu senin grup için bağlantın %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Ağ & sunucular @@ -7119,6 +7115,10 @@ Enable in *Network & servers* settings. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications Anında bildirimler @@ -8677,10 +8677,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation SimpleX tek kullanımlık davet @@ -8691,6 +8687,10 @@ copied message info SimpleX protokolleri Trail of Bits tarafından incelenmiştir. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff index 09fac6e407..fe69dea6ab 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -5921,10 +5921,6 @@ This is your link for group %@! Name not found No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers Мережа та сервери @@ -7130,6 +7126,10 @@ Enable in *Network & servers* settings. Public channels - speak freely 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications Push-сповіщення @@ -8687,10 +8687,6 @@ copied message info SimpleX name not verified alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation Одноразове запрошення SimpleX @@ -8701,6 +8697,10 @@ copied message info Протоколи SimpleX, розглянуті Trail of Bits. No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address simplex link type diff --git a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff index 03f0095b06..1f6067fe53 100644 --- a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff @@ -6043,10 +6043,6 @@ This is your link for group %@! 未找到名称 No comment provided by engineer. - - Public names for your channel or business. - No comment provided by engineer. - Network & servers 网络和服务器 @@ -7302,6 +7298,10 @@ Enable in *Network & servers* settings. 公开频道 - 自由发言 🚀 No comment provided by engineer. + + Public names for your channel or business. + No comment provided by engineer. + Push notifications 推送通知 @@ -8901,10 +8901,6 @@ copied message info SimpleX 名称未验证 alert title - - SimpleX public names (BETA) - No comment provided by engineer. - SimpleX one-time invitation SimpleX 一次性邀请 @@ -8915,6 +8911,10 @@ copied message info SimpleX 协议由 Trail of Bits 审阅。 No comment provided by engineer. + + SimpleX public names (BETA) + No comment provided by engineer. + SimpleX relay address SimpleX 中继地址 diff --git a/apps/ios/SimpleX SE/ru.lproj/Localizable.strings b/apps/ios/SimpleX SE/ru.lproj/Localizable.strings index cade4afe9a..0b942b1b27 100644 --- a/apps/ios/SimpleX SE/ru.lproj/Localizable.strings +++ b/apps/ios/SimpleX SE/ru.lproj/Localizable.strings @@ -106,3 +106,6 @@ /* No comment provided by engineer. */ "Wrong database passphrase" = "Неправильный пароль базы данных"; +/* No comment provided by engineer. */ +"You can allow sharing in Your privacy / SimpleX Lock settings." = "Вы можете разрешить отправку в настройках Конфиденциальность / Блокировка SimpleX."; + diff --git a/apps/ios/de.lproj/Localizable.strings b/apps/ios/de.lproj/Localizable.strings index aad92b89bb..41f64e5400 100644 --- a/apps/ios/de.lproj/Localizable.strings +++ b/apps/ios/de.lproj/Localizable.strings @@ -3256,7 +3256,7 @@ servers warning */ "How to" = "Anleitung"; /* No comment provided by engineer. */ -"How to register a test name" = "Einen Test-Namen registrieren"; +"How to register a test name" = "Wie man einen Test-Namen registriert"; /* No comment provided by engineer. */ "How to use it" = "Wie man SimpleX nutzt"; @@ -4029,9 +4029,6 @@ servers warning */ /* No comment provided by engineer. */ "Name not found" = "Name wurde nicht gefunden"; -/* No comment provided by engineer. */ -"Names for your channel or business." = "Namen für Ihren Kanal oder Ihr Unternehmen."; - /* No comment provided by engineer. */ "Network & servers" = "Netzwerk und Server"; @@ -4837,6 +4834,9 @@ alert title */ /* No comment provided by engineer. */ "Public channels - speak freely 🚀" = "Öffentliche Kanäle – frei sprechen 🚀"; +/* No comment provided by engineer. */ +"Public names for your channel or business." = "Öffentliche Namen für Ihren Kanal oder Ihr Unternehmen."; + /* No comment provided by engineer. */ "Push notifications" = "Push-Benachrichtigungen"; @@ -5893,15 +5893,15 @@ copied message info */ /* alert title */ "SimpleX name not verified" = "SimpleX-Name ist nicht verifiziert"; -/* No comment provided by engineer. */ -"SimpleX names (BETA)" = "SimpleX-Namen (BETA)"; - /* simplex link type */ "SimpleX one-time invitation" = "SimpleX-Einmal-Einladung"; /* No comment provided by engineer. */ "SimpleX protocols reviewed by Trail of Bits." = "Die SimpleX-Protokolle wurden von Trail of Bits überprüft."; +/* No comment provided by engineer. */ +"SimpleX public names (BETA)" = "Öffentliche SimpleX-Namen (BETA)"; + /* simplex link type */ "SimpleX relay address" = "SimpleX Relais-Adresse"; diff --git a/apps/ios/es.lproj/Localizable.strings b/apps/ios/es.lproj/Localizable.strings index dfca8affad..a6d4e9d20c 100644 --- a/apps/ios/es.lproj/Localizable.strings +++ b/apps/ios/es.lproj/Localizable.strings @@ -487,6 +487,12 @@ swipe action */ /* No comment provided by engineer. */ "Add address to your profile, so that your SimpleX contacts can share it with other people. Profile update will be sent to your SimpleX contacts." = "Añade la dirección a tu perfil para que tus contactos SimpleX puedan compartirla con otros. La actualización del perfil se enviará a tus contactos SimpleX."; +/* No comment provided by engineer. */ +"Add contributors." = "Añade colaboradores."; + +/* No comment provided by engineer. */ +"Add description" = "Añadir descripción"; + /* No comment provided by engineer. */ "Add friends" = "Añadir amigos"; @@ -931,6 +937,9 @@ swipe action */ /* No comment provided by engineer. */ "Better calls" = "Llamadas mejoradas"; +/* No comment provided by engineer. */ +"Better channels 📢" = "Canales mejorados 📢"; + /* No comment provided by engineer. */ "Better groups" = "Grupos mejorados"; @@ -1221,6 +1230,9 @@ alert subtitle */ /* alert message */ "Channel profile was changed. If you save it, the updated profile will be sent to channel subscribers." = "El perfil del canal ha sido modificado. Si lo guardas, el perfil actualizado será enviado a los suscriptores."; +/* No comment provided by engineer. */ +"Channel SimpleX name" = "Nombre SimpleX del canal"; + /* alert title */ "Channel temporarily unavailable" = "Canales no disponibles temporalmente"; @@ -1766,6 +1778,9 @@ server test step */ /* No comment provided by engineer. */ "Create SimpleX address" = "Crear dirección SimpleX"; +/* No comment provided by engineer. */ +"Create web preview." = "Crea previsualizaciones web."; + /* No comment provided by engineer. */ "Create your address" = "Crea tu dirección"; @@ -2228,6 +2243,9 @@ alert button */ /* No comment provided by engineer. */ "Do it later" = "Hacer más tarde"; +/* No comment provided by engineer. */ +"Do not require signing messages." = "No requerir la firma de mensajes."; + /* No comment provided by engineer. */ "Do not send history to new members." = "No se envía el historial a los miembros nuevos."; @@ -2258,6 +2276,9 @@ alert button */ /* No comment provided by engineer. */ "Don't miss important messages." = "No pierdas los mensajes importantes."; +/* alert action */ +"Don't save" = "No guardar"; + /* alert action */ "Don't show again" = "No volver a mostrar"; @@ -2316,12 +2337,18 @@ chat item action */ /* No comment provided by engineer. */ "Easier to invite your friends 👋" = "Invitar a tus amigos es más fácil 👋"; +/* No comment provided by engineer. */ +"Easier to read." = "Fácil de leer."; + /* chat item action */ "Edit" = "Editar"; /* No comment provided by engineer. */ "Edit channel profile" = "Editar perfil del canal"; +/* No comment provided by engineer. */ +"Edit description" = "Editar descripción"; + /* No comment provided by engineer. */ "Edit group profile" = "Editar perfil de grupo"; @@ -2478,6 +2505,9 @@ chat item action */ /* No comment provided by engineer. */ "Enter correct passphrase." = "Introduce la contraseña correcta."; +/* placeholder */ +"Enter description (optional)" = "Introduce descripción (opcional)"; + /* No comment provided by engineer. */ "Enter group name…" = "Nombre del grupo…"; @@ -2739,6 +2769,9 @@ chat item action */ /* No comment provided by engineer. */ "Error setting delivery receipts!" = "¡Error al configurar confirmaciones de entrega!"; +/* alert title */ +"Error sharing address" = "Error compartiendo dirección"; + /* alert title */ "Error sharing channel" = "Error al compartir el canal"; @@ -2881,6 +2914,12 @@ server test error */ /* file error text */ "File server error: %@" = "Error del servidor de archivos: %@"; +/* No comment provided by engineer. */ +"File servers" = "Servidores de archivos"; + +/* copied message info */ +"File servers: %@" = "Servidores de archivos: %@"; + /* No comment provided by engineer. */ "File status" = "Estado del archivo"; @@ -3066,6 +3105,9 @@ servers warning */ /* No comment provided by engineer. */ "Get notified when mentioned." = "Las menciones ahora se notifican."; +/* No comment provided by engineer. */ +"Get SimpleX name (BETA)" = "Obtener nombre SimpleX (BETA)"; + /* No comment provided by engineer. */ "Get started" = "Empezar"; @@ -3213,6 +3255,9 @@ servers warning */ /* No comment provided by engineer. */ "How to" = "Cómo"; +/* No comment provided by engineer. */ +"How to register a test name" = "Cómo registrar un nombre de prueba"; + /* No comment provided by engineer. */ "How to use it" = "Guía de uso"; @@ -3675,6 +3720,9 @@ servers warning */ /* No comment provided by engineer. */ "Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." = "Asegúrate de que las direcciones del servidor WebRTC ICE tienen el formato correcto, están separadas por líneas y no duplicadas."; +/* No comment provided by engineer. */ +"Manage your relays." = "Gestiona tus servidores."; + /* No comment provided by engineer. */ "Mark deleted for everyone" = "Marcar como eliminado para todos"; @@ -3825,6 +3873,12 @@ servers warning */ /* No comment provided by engineer. */ "Message shape" = "Forma del mensaje"; +/* No comment provided by engineer. */ +"Message signing is not required." = "Los mensajes firmados no son obligatorios."; + +/* No comment provided by engineer. */ +"Message signing is required." = "Los mensajes firmados son obligatorios."; + /* No comment provided by engineer. */ "Message source remains private." = "El autor del mensaje se mantiene privado."; @@ -4780,6 +4834,9 @@ alert title */ /* No comment provided by engineer. */ "Public channels - speak freely 🚀" = "Canales públicos - habla con libertad 🚀"; +/* No comment provided by engineer. */ +"Public names for your channel or business." = "Nombres públicos para tu canal o negocio."; + /* No comment provided by engineer. */ "Push notifications" = "Notificaciones push"; @@ -4977,6 +5034,9 @@ swipe action */ /* alert title */ "Remove member?" = "¿Expulsar miembro?"; +/* No comment provided by engineer. */ +"Remove name" = "Eliminar nombre"; + /* No comment provided by engineer. */ "Remove passphrase from keychain?" = "¿Eliminar contraseña de Keychain?"; @@ -5085,6 +5145,9 @@ swipe action */ /* chat list item title */ "requested to connect" = "solicitado para conectar"; +/* No comment provided by engineer. */ +"Require signing messages." = "Requerir la firma de mensajes."; + /* No comment provided by engineer. */ "Required" = "Obligatorio"; @@ -5261,6 +5324,9 @@ chat item action */ /* alert title */ "Save servers?" = "¿Guardar servidores?"; +/* alert title */ +"Save SimpleX name?" = "¿Guardar el nombre SimpleX?"; + /* alert title */ "Save webpage settings?" = "¿Guardar la configuración web?"; @@ -5721,6 +5787,9 @@ chat item action */ /* No comment provided by engineer. */ "Show developer options" = "Mostrar opciones de desarrollador"; +/* No comment provided by engineer. */ +"Show encryption" = "Mostrar cifrado"; + /* No comment provided by engineer. */ "Show last messages" = "Mostrar último mensaje"; @@ -5739,6 +5808,25 @@ chat item action */ /* No comment provided by engineer. */ "Show:" = "Muestra:"; +/* No comment provided by engineer. */ +"Sign message" = "Firmar mensaje"; + +/* chat feature */ +"Sign messages" = "Firmar mensajes"; + +/* alert title +copied message info */ +"Signature missing" = "Falta la firma"; + +/* copied message info */ +"Signed" = "Firmado"; + +/* copied message info */ +"Signed & verified" = "Firmado y verificado"; + +/* No comment provided by engineer. */ +"Signing proves you authored this message and can't be denied later." = "La firma prueba que eres el autor del mensaje sin posibilidad de repudio."; + /* No comment provided by engineer. */ "SimpleX" = "SimpleX"; @@ -5811,6 +5899,9 @@ chat item action */ /* No comment provided by engineer. */ "SimpleX protocols reviewed by Trail of Bits." = "Protocolos de SimpleX auditados por Trail of Bits."; +/* No comment provided by engineer. */ +"SimpleX public names (BETA)" = "Nombres públicos SimpleX (BETA)"; + /* simplex link type */ "SimpleX relay address" = "Dirección de servidor SimpleX"; @@ -6125,6 +6216,9 @@ server test failure */ /* badge alert */ "The badge is signed with a key that this version of the app does not recognize. Update the app to verify this badge." = "La insignia está firmada con una clave que esta versión de la app no reconoce. Actualiza la app para verificar la insignia."; +/* alert message */ +"The channel required this message to be signed, but the signature is missing." = "El canal requiere que el mensaje esté firmado, pero falta la firma."; + /* No comment provided by engineer. */ "The code you scanned is not a SimpleX link QR code." = "El código QR escaneado no es un enlace de SimpleX."; @@ -6372,6 +6466,9 @@ alert subtitle */ /* No comment provided by engineer. */ "To verify end-to-end encryption with your contact compare (or scan) the code on your devices." = "Para verificar el cifrado de extremo a extremo con tu contacto, compara (o escanea) el código en ambos dispositivos."; +/* No comment provided by engineer. */ +"To verify keys with this subscriber, compare (or scan) the code on your devices." = "Para verificar las claves con este suscriptor, compara (o escanea) el código en ambos dispositivos."; + /* No comment provided by engineer. */ "Toggle incognito when connecting." = "Activa incógnito al conectar."; diff --git a/apps/ios/hu.lproj/Localizable.strings b/apps/ios/hu.lproj/Localizable.strings index 4e9ffe056c..330688163e 100644 --- a/apps/ios/hu.lproj/Localizable.strings +++ b/apps/ios/hu.lproj/Localizable.strings @@ -4029,9 +4029,6 @@ servers warning */ /* No comment provided by engineer. */ "Name not found" = "Nem található a név"; -/* No comment provided by engineer. */ -"Names for your channel or business." = "Nevek a csatornákhoz vagy az üzleti profilokhoz."; - /* No comment provided by engineer. */ "Network & servers" = "Hálózat és kiszolgálók"; @@ -4837,6 +4834,9 @@ alert title */ /* No comment provided by engineer. */ "Public channels - speak freely 🚀" = "Nyilvános csatornák – mondja el szabadon a véleményét 🚀"; +/* No comment provided by engineer. */ +"Public names for your channel or business." = "Nyilvános nevek a csatornákhoz vagy az üzleti profilokhoz."; + /* No comment provided by engineer. */ "Push notifications" = "Leküldéses értesítések"; @@ -5893,15 +5893,15 @@ copied message info */ /* alert title */ "SimpleX name not verified" = "Nincs ellenőrizve a SimpleX-név"; -/* No comment provided by engineer. */ -"SimpleX names (BETA)" = "SimpleX-nevek (béta)"; - /* simplex link type */ "SimpleX one-time invitation" = "Egyszer használható SimpleX meghívó"; /* No comment provided by engineer. */ "SimpleX protocols reviewed by Trail of Bits." = "A SimpleX protokollokat a Trail of Bits auditálta."; +/* No comment provided by engineer. */ +"SimpleX public names (BETA)" = "Nyilvános SimpleX-nevek (béta)"; + /* simplex link type */ "SimpleX relay address" = "SimpleX-átjátszó címe"; diff --git a/apps/ios/it.lproj/Localizable.strings b/apps/ios/it.lproj/Localizable.strings index 5dc200ffa2..3544dc1813 100644 --- a/apps/ios/it.lproj/Localizable.strings +++ b/apps/ios/it.lproj/Localizable.strings @@ -4029,9 +4029,6 @@ servers warning */ /* No comment provided by engineer. */ "Name not found" = "Nome non trovato"; -/* No comment provided by engineer. */ -"Names for your channel or business." = "Nomi per il tuo canale o per il lavoro."; - /* No comment provided by engineer. */ "Network & servers" = "Rete e server"; @@ -4837,6 +4834,9 @@ alert title */ /* No comment provided by engineer. */ "Public channels - speak freely 🚀" = "Canali pubblici - parla liberamente 🚀"; +/* No comment provided by engineer. */ +"Public names for your channel or business." = "Nomi pubblici per il tuo canale o per il lavoro."; + /* No comment provided by engineer. */ "Push notifications" = "Notifiche push"; @@ -5893,15 +5893,15 @@ copied message info */ /* alert title */ "SimpleX name not verified" = "Nome SimpleX non verificato"; -/* No comment provided by engineer. */ -"SimpleX names (BETA)" = "Nomi SimpleX (BETA)"; - /* simplex link type */ "SimpleX one-time invitation" = "Invito SimpleX una tantum"; /* No comment provided by engineer. */ "SimpleX protocols reviewed by Trail of Bits." = "Protocolli di SimpleX esaminati da Trail of Bits."; +/* No comment provided by engineer. */ +"SimpleX public names (BETA)" = "Nomi pubblici SimpleX (BETA)"; + /* simplex link type */ "SimpleX relay address" = "Indirizzo del relay SimpleX"; diff --git a/apps/ios/ru.lproj/Localizable.strings b/apps/ios/ru.lproj/Localizable.strings index f70fcf966f..ce7e446211 100644 --- a/apps/ios/ru.lproj/Localizable.strings +++ b/apps/ios/ru.lproj/Localizable.strings @@ -118,6 +118,9 @@ /* No comment provided by engineer. */ "%@ downloaded" = "%@ загружено"; +/* badge alert */ +"%@ invested in SimpleX Chat crowdfunding." = "%@ инвестировал(а) в краудфандинг SimpleX Chat."; + /* notification title */ "%@ is connected!" = "Установлено соединение с %@!"; @@ -133,6 +136,9 @@ /* No comment provided by engineer. */ "%@ servers" = "%@ серверы"; +/* badge alert */ +"%@ supports SimpleX Chat." = "%@ поддерживает SimpleX Chat."; + /* No comment provided by engineer. */ "%@ uploaded" = "%@ загружено"; @@ -151,6 +157,9 @@ /* copied message info */ "%@:" = "%@:"; +/* badge alert */ +"%1$@ supported SimpleX Chat. The badge expired on %2$@." = "%1$@ поддерживал(а) SimpleX Chat. Срок действия значка истёк %2$@."; + /* time interval */ "%d days" = "%d дней"; @@ -178,6 +187,9 @@ /* time interval */ "%d months" = "%d мес"; +/* channel owners count */ +"%d owner" = "%d владелец"; + /* channel owners count */ "%d owners" = "%d владельцев"; @@ -454,6 +466,9 @@ swipe action */ /* No comment provided by engineer. */ "Acknowledged" = "Подтверждено"; +/* No comment provided by engineer. */ +"acknowledged roster" = "подтверждённый список"; + /* No comment provided by engineer. */ "Acknowledgement errors" = "Ошибки подтверждения"; @@ -472,6 +487,12 @@ swipe action */ /* No comment provided by engineer. */ "Add address to your profile, so that your SimpleX contacts can share it with other people. Profile update will be sent to your SimpleX contacts." = "Добавьте адрес в свой профиль, чтобы Ваши SimpleX контакты могли поделиться им. Профиль будет отправлен Вашим SimpleX контактам."; +/* No comment provided by engineer. */ +"Add contributors." = "Добавить соавторов."; + +/* No comment provided by engineer. */ +"Add description" = "Добавить описание"; + /* No comment provided by engineer. */ "Add friends" = "Добавить друзей"; @@ -487,6 +508,12 @@ swipe action */ /* No comment provided by engineer. */ "Add relay" = "Добавить релей"; +/* No comment provided by engineer. */ +"Add relays" = "Добавить релеи"; + +/* No comment provided by engineer. */ +"Add relays to restore message delivery." = "Добавить релеи для восстановления доставки сообщений."; + /* No comment provided by engineer. */ "Add server" = "Добавить сервер"; @@ -496,6 +523,9 @@ swipe action */ /* No comment provided by engineer. */ "Add team members" = "Добавить сотрудников"; +/* No comment provided by engineer. */ +"Add this code to your webpage. It will display the preview of your channel / group." = "Добавьте этот код на свой веб-сайт. Он отобразит предпросмотр вашего канала или группы."; + /* No comment provided by engineer. */ "Add to another device" = "Добавить на другое устройство"; @@ -550,6 +580,9 @@ swipe action */ /* No comment provided by engineer. */ "Advanced network settings" = "Настройки сети"; +/* No comment provided by engineer. */ +"Advanced options" = "Продвинутые настройки"; + /* No comment provided by engineer. */ "Advanced settings" = "Дополнительные настройки"; @@ -628,6 +661,9 @@ swipe action */ /* No comment provided by engineer. */ "Allow" = "Разрешить"; +/* No comment provided by engineer. */ +"Allow anyone to embed" = "Разрешить всем встраивать"; + /* No comment provided by engineer. */ "Allow calls only if your contact allows them." = "Разрешить звонки, только если их разрешает Ваш контакт."; @@ -739,6 +775,9 @@ swipe action */ /* No comment provided by engineer. */ "Answer call" = "Принять звонок"; +/* No comment provided by engineer. */ +"Any webpage can show the preview." = "Предпросмотр можно отобразить на любой веб-странице."; + /* No comment provided by engineer. */ "App build: %@" = "Сборка приложения: %@"; @@ -763,6 +802,9 @@ swipe action */ /* No comment provided by engineer. */ "App session" = "Сессия приложения"; +/* alert title */ +"App update required" = "Необходимо обновление приложения"; + /* No comment provided by engineer. */ "App version" = "Версия приложения"; @@ -880,6 +922,9 @@ swipe action */ /* No comment provided by engineer. */ "Bad message ID" = "Ошибка ID сообщения"; +/* badge alert title */ +"Badge cannot be verified" = "Не удалось проверить подлинность значка"; + /* No comment provided by engineer. */ "Be free\nin your network" = "Будь свободен\nв своей сети"; @@ -892,6 +937,9 @@ swipe action */ /* No comment provided by engineer. */ "Better calls" = "Улучшенные звонки"; +/* No comment provided by engineer. */ +"Better channels 📢" = "Улучшенные каналы 📢"; + /* No comment provided by engineer. */ "Better groups" = "Улучшенные группы"; @@ -1066,6 +1114,12 @@ alert button new chat action */ "Cancel" = "Отменить"; +/* No comment provided by engineer. */ +"Cancel and delete channel" = "Отменить и удалить канал"; + +/* alert title */ +"Cancel creating channel?" = "Отменить создание канала?"; + /* No comment provided by engineer. */ "Cancel migration" = "Отменить миграцию"; @@ -1114,6 +1168,9 @@ new chat action */ /* No comment provided by engineer. */ "Change role" = "Поменять роль"; +/* No comment provided by engineer. */ +"Change role?" = "Изменить роль?"; + /* authentication reason */ "Change self-destruct mode" = "Изменить режим самоуничтожения"; @@ -1173,15 +1230,24 @@ alert subtitle */ /* alert message */ "Channel profile was changed. If you save it, the updated profile will be sent to channel subscribers." = "Профиль канала был изменен. Если Вы сохраните его, обновлённый профиль будет отправлен подписчикам канала."; +/* No comment provided by engineer. */ +"Channel SimpleX name" = "SimpleX имя канала"; + /* alert title */ "Channel temporarily unavailable" = "Канал временно недоступен"; +/* No comment provided by engineer. */ +"Channel webpage" = "Веб-страница канала"; + /* No comment provided by engineer. */ "Channel will be deleted for all subscribers - this cannot be undone!" = "Канал будет удалён для всех подписчиков - это нельзя отменить!"; /* No comment provided by engineer. */ "Channel will be deleted for you - this cannot be undone!" = "Канал будет удалён для Вас - это нельзя отменить!"; +/* alert message */ +"Channel will start working with %d of %d relays. Continue?" = "Канал начнёт работу с %1$d из %2$d релеев. Продолжить?"; + /* No comment provided by engineer. */ "Channels" = "Каналы"; @@ -1200,6 +1266,9 @@ alert subtitle */ /* No comment provided by engineer. */ "Chat console" = "Консоль"; +/* No comment provided by engineer. */ +"Chat data" = "Данные чата"; + /* No comment provided by engineer. */ "Chat database" = "Архив чата"; @@ -1433,6 +1502,9 @@ server test step */ /* No comment provided by engineer. */ "Connect faster! 🚀" = "Соединяйтесь быстрее! 🚀"; +/* new chat action */ +"Connect to %@" = "Соединиться с %@"; + /* No comment provided by engineer. */ "Connect to desktop" = "Подключиться к компьютеру"; @@ -1523,6 +1595,9 @@ server test step */ /* No comment provided by engineer. */ "Connection blocked" = "Соединение заблокировано"; +/* conn error description */ +"Connection blocked: %@" = "Соединение заблокировано: %@"; + /* alert title */ "Connection error" = "Ошибка соединения"; @@ -1640,12 +1715,18 @@ server test step */ /* No comment provided by engineer. */ "Contribute" = "Внести свой вклад"; +/* member role */ +"contributor" = "соавтор"; + /* No comment provided by engineer. */ "Conversation deleted!" = "Разговор удалён!"; /* No comment provided by engineer. */ "Copy" = "Копировать"; +/* No comment provided by engineer. */ +"Copy code" = "Скопировать код"; + /* No comment provided by engineer. */ "Copy error" = "Скопировать ошибку"; @@ -1664,6 +1745,9 @@ server test step */ /* No comment provided by engineer. */ "Create a group using a random profile." = "Создайте группу, используя случайный профиль."; +/* No comment provided by engineer. */ +"Create a webpage to show your channel preview to visitors before they subscribe. Host it yourself or use any static hosting." = "Создайте веб-страницу, чтобы показывать предпросмотр Вашего канала посетителям до подписки. Хостите её сами или используйте любой статический хостинг."; + /* server test step */ "Create file" = "Создание файла"; @@ -1694,6 +1778,9 @@ server test step */ /* No comment provided by engineer. */ "Create SimpleX address" = "Создать адрес SimpleX"; +/* No comment provided by engineer. */ +"Create web preview." = "Создать веб-предпросмотр."; + /* No comment provided by engineer. */ "Create your address" = "Создайте Ваш адрес"; @@ -1921,6 +2008,9 @@ swipe action */ /* No comment provided by engineer. */ "Delete for me" = "Удалить для меня"; +/* No comment provided by engineer. */ +"Delete from history" = "Удалить из истории"; + /* No comment provided by engineer. */ "Delete group" = "Удалить группу"; @@ -2153,6 +2243,9 @@ alert button */ /* No comment provided by engineer. */ "Do it later" = "Отложить"; +/* No comment provided by engineer. */ +"Do not require signing messages." = "Не требовать подпись сообщений."; + /* No comment provided by engineer. */ "Do not send history to new members." = "Не отправлять историю новым членам."; @@ -2183,6 +2276,9 @@ alert button */ /* No comment provided by engineer. */ "Don't miss important messages." = "Не пропустите важные сообщения."; +/* alert action */ +"Don't save" = "Не сохранять"; + /* alert action */ "Don't show again" = "Не показывать"; @@ -2241,12 +2337,18 @@ chat item action */ /* No comment provided by engineer. */ "Easier to invite your friends 👋" = "Проще пригласить друзей 👋"; +/* No comment provided by engineer. */ +"Easier to read." = "Легче для чтения."; + /* chat item action */ "Edit" = "Редактировать"; /* No comment provided by engineer. */ "Edit channel profile" = "Редактировать профиль канала"; +/* No comment provided by engineer. */ +"Edit description" = "Редактировать описание"; + /* No comment provided by engineer. */ "Edit group profile" = "Редактировать профиль группы"; @@ -2403,6 +2505,9 @@ chat item action */ /* No comment provided by engineer. */ "Enter correct passphrase." = "Введите правильный пароль."; +/* placeholder */ +"Enter description (optional)" = "Введите описание (необязательно)"; + /* No comment provided by engineer. */ "Enter group name…" = "Введите имя группы…"; @@ -2430,6 +2535,9 @@ chat item action */ /* No comment provided by engineer. */ "Enter this device name…" = "Введите имя этого устройства…"; +/* No comment provided by engineer. */ +"Enter webpage URL" = "Введите адрес страницы"; + /* placeholder */ "Enter welcome message…" = "Введите приветственное сообщение…"; @@ -2463,6 +2571,9 @@ chat item action */ /* alert title */ "Error adding relay" = "Ошибка добавления релея"; +/* alert title */ +"Error adding relays" = "Ошибка добавления релеев"; + /* alert title */ "Error adding server" = "Ошибка добавления сервера"; @@ -2541,6 +2652,9 @@ chat item action */ /* alert title */ "Error deleting database" = "Ошибка при удалении данных чата"; +/* alert title */ +"Error deleting message" = "Ошибка удаления сообщения"; + /* alert title */ "Error deleting old database" = "Ошибка при удалении предыдущей версии данных чата"; @@ -2619,6 +2733,9 @@ chat item action */ /* No comment provided by engineer. */ "Error saving ICE servers" = "Ошибка при сохранении ICE-серверов"; +/* alert title */ +"Error saving name" = "Ошибка сохранения имени"; + /* No comment provided by engineer. */ "Error saving passcode" = "Ошибка сохранения кода"; @@ -2652,6 +2769,9 @@ chat item action */ /* No comment provided by engineer. */ "Error setting delivery receipts!" = "Ошибка настроек отчётов о доставке!"; +/* alert title */ +"Error sharing address" = "Ошибка отправки адреса"; + /* alert title */ "Error sharing channel" = "Ошибка при публикации канала"; @@ -2794,6 +2914,12 @@ server test error */ /* file error text */ "File server error: %@" = "Ошибка сервера файлов: %@"; +/* No comment provided by engineer. */ +"File servers" = "Серверы файлов"; + +/* copied message info */ +"File servers: %@" = "Серверы файлов: %@"; + /* No comment provided by engineer. */ "File status" = "Статус файла"; @@ -2979,6 +3105,9 @@ servers warning */ /* No comment provided by engineer. */ "Get notified when mentioned." = "Уведомления, когда Вас упомянули."; +/* No comment provided by engineer. */ +"Get SimpleX name (BETA)" = "Зарегистрировать SimpleX имя (BETA)"; + /* No comment provided by engineer. */ "Get started" = "Начать"; @@ -3054,6 +3183,9 @@ servers warning */ /* alert message */ "Group profile was changed. If you save it, the updated profile will be sent to group members." = "Профиль группы изменен. Если Вы сохраните его, новый профиль будет отправлен членам группы."; +/* No comment provided by engineer. */ +"Group webpage" = "Веб-страница группы"; + /* No comment provided by engineer. */ "Group welcome message" = "Приветственное сообщение группы"; @@ -3069,6 +3201,9 @@ servers warning */ /* No comment provided by engineer. */ "Help" = "Помощь"; +/* No comment provided by engineer. */ +"Help & support" = "Помощь и поддержка"; + /* No comment provided by engineer. */ "Help admins moderating their groups." = "Помогайте админам модерировать их группы."; @@ -3120,12 +3255,18 @@ servers warning */ /* No comment provided by engineer. */ "How to" = "Инфо"; +/* No comment provided by engineer. */ +"How to register a test name" = "Как зарегистрировать тестовое имя"; + /* No comment provided by engineer. */ "How to use it" = "Как использовать"; /* No comment provided by engineer. */ "How to use your servers" = "Как использовать серверы"; +/* No comment provided by engineer. */ +"https://" = "https://"; + /* No comment provided by engineer. */ "Hungarian interface" = "Венгерский интерфейс"; @@ -3405,6 +3546,9 @@ servers warning */ /* No comment provided by engineer. */ "It seems like you are already connected via this link. If it is not the case, there was an error (%@)." = "Возможно, Вы уже соединились через эту ссылку. Если это не так, то это ошибка (%@)."; +/* No comment provided by engineer. */ +"It will be shown to subscribers and used to allow loading the preview." = "Адрес будет показан подписчикам и разрешит загрузку предпросмотра."; + /* No comment provided by engineer. */ "Italian interface" = "Итальянский интерфейс"; @@ -3418,11 +3562,14 @@ servers warning */ "Join" = "Вступить"; /* No comment provided by engineer. */ -"Join as %@" = "Вступить как %s"; +"Join as %@" = "Вступить как %@"; /* No comment provided by engineer. */ "Join channel" = "Вступить в канал"; +/* new chat action */ +"Join channel %@" = "Вступить в канал %@"; + /* new chat sheet title */ "Join group" = "Вступить в группу"; @@ -3495,6 +3642,12 @@ servers warning */ /* No comment provided by engineer. */ "Less traffic on mobile networks." = "Меньше трафик в мобильных сетях."; +/* No comment provided by engineer. */ +"Let people connect to you via name registered with your SimpleX address." = "Позвольте людям соединяться с Вами через имя, зарегистрированное для Вашего SimpleX адреса."; + +/* No comment provided by engineer. */ +"Let people join via name registered with this channel link." = "Позвольте людям вступать через имя, зарегистрированное для ссылки этого канала."; + /* No comment provided by engineer. */ "Let someone connect to you" = "Дайте собеседнику Вашу ссылку"; @@ -3567,6 +3720,9 @@ servers warning */ /* No comment provided by engineer. */ "Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." = "Пожалуйста, проверьте, что адреса WebRTC ICE-серверов имеют правильный формат, каждый адрес на отдельной строке и не повторяется."; +/* No comment provided by engineer. */ +"Manage your relays." = "Управлять своими релеями."; + /* No comment provided by engineer. */ "Mark deleted for everyone" = "Пометить как удалённое для всех"; @@ -3717,6 +3873,12 @@ servers warning */ /* No comment provided by engineer. */ "Message shape" = "Форма сообщений"; +/* No comment provided by engineer. */ +"Message signing is not required." = "Подпись сообщений не обязательна."; + +/* No comment provided by engineer. */ +"Message signing is required." = "Подпись сообщений обязательна."; + /* No comment provided by engineer. */ "Message source remains private." = "Источник сообщения остаётся конфиденциальным."; @@ -3837,6 +3999,9 @@ servers warning */ /* No comment provided by engineer. */ "More improvements are coming soon!" = "Дополнительные улучшения скоро!"; +/* No comment provided by engineer. */ +"More privacy" = "Больше конфиденциальности"; + /* No comment provided by engineer. */ "More reliable network connection." = "Более надёжное соединение с сетью."; @@ -3861,6 +4026,9 @@ servers warning */ /* swipe action */ "Name" = "Имя"; +/* No comment provided by engineer. */ +"Name not found" = "Имя не найдено"; + /* No comment provided by engineer. */ "Network & servers" = "Сеть и серверы"; @@ -3981,6 +4149,9 @@ servers warning */ /* Authentication unavailable */ "No app password" = "Нет кода доступа"; +/* No comment provided by engineer. */ +"No available relays" = "Нет доступных релеев"; + /* No comment provided by engineer. */ "No chat relays" = "Нет чат-релеев"; @@ -4059,6 +4230,9 @@ servers warning */ /* No comment provided by engineer. */ "No received or sent files" = "Нет полученных или отправленных файлов"; +/* No comment provided by engineer. */ +"No relays" = "Релеи отсутствуют"; + /* servers error */ "No servers for private message routing." = "Нет серверов для доставки сообщений."; @@ -4068,6 +4242,9 @@ servers warning */ /* servers error */ "No servers to receive messages." = "Нет серверов для приёма сообщений."; +/* servers warning */ +"No servers to resolve names." = "Нет серверов для разрешения имён."; + /* servers error */ "No servers to send files." = "Нет серверов для отправки файлов."; @@ -4083,12 +4260,18 @@ servers warning */ /* No comment provided by engineer. */ "No unread chats" = "Нет непрочитанных чатов"; +/* No comment provided by engineer. */ +"No valid link" = "Нет действительной ссылки"; + /* No comment provided by engineer. */ "Nobody tracked your conversations. No one drew a map of where you'd been. Privacy was never a feature - it was the way of life." = "Никто не отслеживал ваши разговоры. Никто не составлял карту ваших перемещений. Конфиденциальность не была функцией - это был образ жизни."; /* No comment provided by engineer. */ "Non-profit governance" = "Некоммерческое управление"; +/* No comment provided by engineer. */ +"None of your servers are set to resolve SimpleX names. Configure servers, or use a connection link." = "Ни один из Ваших серверов не настроен для разрешения SimpleX имён. Настройте серверы или используйте ссылку для соединения."; + /* No comment provided by engineer. */ "Not a better lock on someone else's door. Not a nicer landlord that respects your privacy, but still keeps the record of all visitors. You are not a guest. You are home. No king can enter it - you are sovereign." = "Не более надёжный замок на чужой двери. Не более вежливый хозяин, который уважает вашу частную жизнь, но всё равно ведёт учёт всех посетителей. Вы не гость. Вы у себя дома. Ни один король не войдёт в ваш дом - вы суверенны."; @@ -4241,6 +4424,9 @@ new chat action */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Только Ваш контакт может отправлять голосовые сообщения."; +/* No comment provided by engineer. */ +"Only your page above can show the preview." = "Предпросмотр можно отобразить только на Вашей странице, указанной выше."; + /* alert action alert button */ "Open" = "Открыть"; @@ -4362,6 +4548,9 @@ alert button */ /* feature role */ "owners" = "владельцы"; +/* No comment provided by engineer. */ +"Owners & contributors" = "Владельцы и соавторы"; + /* No comment provided by engineer. */ "Ownership: you can run your own relays." = "Владение: Вы можете запустить свои собственные релеи."; @@ -4645,6 +4834,9 @@ alert title */ /* No comment provided by engineer. */ "Public channels - speak freely 🚀" = "Публичные каналы - говорите свободно 🚀"; +/* No comment provided by engineer. */ +"Public names for your channel or business." = "Публичные имена для Вашего канала или бизнеса."; + /* No comment provided by engineer. */ "Push notifications" = "Доставка уведомлений"; @@ -4812,6 +5004,12 @@ swipe action */ /* No comment provided by engineer. */ "Relay test failed!" = "Тест релея не пройден!"; +/* alert message */ +"Relay will be removed from channel - this cannot be undone!" = "Релей будет удалён из канала - это нельзя отменить!"; + +/* alert message */ +"Relays added: %@." = "Добавлены релеи: %@."; + /* No comment provided by engineer. */ "Reliability: many relays per channel." = "Надёжность: несколько релеев на каждый канал."; @@ -4836,9 +5034,18 @@ swipe action */ /* alert title */ "Remove member?" = "Удалить члена группы?"; +/* No comment provided by engineer. */ +"Remove name" = "Удалить имя"; + /* No comment provided by engineer. */ "Remove passphrase from keychain?" = "Удалить пароль из Keychain?"; +/* No comment provided by engineer. */ +"Remove relay" = "Удалить релей"; + +/* alert title */ +"Remove relay?" = "Удалить релей?"; + /* alert title */ "Remove subscriber?" = "Удалить подписчика?"; @@ -4938,6 +5145,9 @@ swipe action */ /* chat list item title */ "requested to connect" = "запрошено соединение"; +/* No comment provided by engineer. */ +"Require signing messages." = "Требовать подпись сообщений."; + /* No comment provided by engineer. */ "Required" = "Обязательно"; @@ -4965,6 +5175,9 @@ swipe action */ /* No comment provided by engineer. */ "Reset to user theme" = "Сбросить на тему пользователя"; +/* No comment provided by engineer. */ +"Resolver error: %@" = "Ошибка разрешения имени: %@"; + /* No comment provided by engineer. */ "Restart the app to create a new chat profile" = "Перезапустите приложение, чтобы создать новый профиль"; @@ -5025,6 +5238,9 @@ swipe action */ /* No comment provided by engineer. */ "Role will be changed to \"%@\". All group members will be notified." = "Роль члена будет изменена на \"%@\". Все члены группы получат уведомление."; +/* No comment provided by engineer. */ +"Role will be changed to \"%@\". All subscribers will be notified." = "Роль будет изменена на \"%@\". Все подписчики получат сообщение."; + /* No comment provided by engineer. */ "Role will be changed to \"%@\". The member will receive a new invitation." = "Роль члена будет изменена на \"%@\". Будет отправлено новое приглашение."; @@ -5063,6 +5279,9 @@ chat item action */ /* No comment provided by engineer. */ "Save and notify group members" = "Сохранить и уведомить членов группы"; +/* No comment provided by engineer. */ +"Save and notify members" = "Сохранить и уведомить членов группы"; + /* No comment provided by engineer. */ "Save and notify subscribers" = "Сохранить и уведомить подписчиков"; @@ -5105,6 +5324,12 @@ chat item action */ /* alert title */ "Save servers?" = "Сохранить серверы?"; +/* alert title */ +"Save SimpleX name?" = "Сохранить SimpleX имя?"; + +/* alert title */ +"Save webpage settings?" = "Сохранить настройки веб-страницы?"; + /* No comment provided by engineer. */ "Save welcome message?" = "Сохранить приветственное сообщение?"; @@ -5363,6 +5588,9 @@ chat item action */ /* No comment provided by engineer. */ "Server" = "Сервер"; +/* No comment provided by engineer. */ +"Server %@ does not support name resolution. Configure servers, or use a connection link." = "Сервер %@ не поддерживает разрешение имён. Настройте серверы или используйте ссылку для соединения."; + /* alert message */ "Server added to operator %@." = "Сервер добавлен к оператору %@."; @@ -5559,6 +5787,9 @@ chat item action */ /* No comment provided by engineer. */ "Show developer options" = "Показать опции для разработчиков"; +/* No comment provided by engineer. */ +"Show encryption" = "Показывать шифрование"; + /* No comment provided by engineer. */ "Show last messages" = "Показывать последние сообщения"; @@ -5577,6 +5808,25 @@ chat item action */ /* No comment provided by engineer. */ "Show:" = "Показать:"; +/* No comment provided by engineer. */ +"Sign message" = "Подписать сообщение"; + +/* chat feature */ +"Sign messages" = "Подпись сообщений"; + +/* alert title +copied message info */ +"Signature missing" = "Подпись отсутствует"; + +/* copied message info */ +"Signed" = "Подписано"; + +/* copied message info */ +"Signed & verified" = "Подписано и проверено"; + +/* No comment provided by engineer. */ +"Signing proves you authored this message and can't be denied later." = "Подпись доказывает, что Вы — автор этого сообщения, и это нельзя будет отрицать."; + /* No comment provided by engineer. */ "SimpleX" = "SimpleX"; @@ -5634,12 +5884,24 @@ chat item action */ /* No comment provided by engineer. */ "SimpleX Lock turned on" = "Блокировка SimpleX включена"; +/* No comment provided by engineer. */ +"SimpleX name" = "SimpleX имя"; + +/* No comment provided by engineer. */ +"SimpleX name error" = "Ошибка SimpleX имени"; + +/* alert title */ +"SimpleX name not verified" = "SimpleX имя не проверено"; + /* simplex link type */ "SimpleX one-time invitation" = "SimpleX одноразовая ссылка"; /* No comment provided by engineer. */ "SimpleX protocols reviewed by Trail of Bits." = "Аудит SimpleX протоколов от Trail of Bits."; +/* No comment provided by engineer. */ +"SimpleX public names (BETA)" = "Публичные SimpleX имена (BETA)"; + /* simplex link type */ "SimpleX relay address" = "Адрес релея SimpleX"; @@ -5716,6 +5978,9 @@ report reason */ /* No comment provided by engineer. */ "Statistics" = "Статистика"; +/* No comment provided by engineer. */ +"Status" = "Статус"; + /* No comment provided by engineer. */ "Stop" = "Остановить"; @@ -5764,6 +6029,9 @@ report reason */ /* No comment provided by engineer. */ "Subscribed" = "Подписано"; +/* member role */ +"subscriber" = "подписчик"; + /* No comment provided by engineer. */ "Subscriber" = "Подписчик"; @@ -5812,6 +6080,9 @@ report reason */ /* No comment provided by engineer. */ "Subscriptions ignored" = "Подписок игнорировано"; +/* No comment provided by engineer. */ +"Support the project" = "Поддержать проект"; + /* No comment provided by engineer. */ "Switch audio and video during the call." = "Переключайте звук и видео во время звонка."; @@ -5942,6 +6213,12 @@ server test failure */ /* No comment provided by engineer. */ "The attempt to change database passphrase was not completed." = "Попытка поменять пароль базы данных не была завершена."; +/* badge alert */ +"The badge is signed with a key that this version of the app does not recognize. Update the app to verify this badge." = "Этот значок подписан ключом, который неизвестен текущей версии приложения. Обновите приложение, чтобы проверить его подлинность."; + +/* alert message */ +"The channel required this message to be signed, but the signature is missing." = "Канал требует подпись сообщений, но у этого сообщения подпись отсутствует."; + /* No comment provided by engineer. */ "The code you scanned is not a SimpleX link QR code." = "Этот QR-код не является SimpleX-ccылкой."; @@ -5994,7 +6271,7 @@ server test failure */ "The oldest human freedom - to speak to another person without being watched - built on infrastructure that cannot betray it." = "Древнейшая человеческая свобода - говорить с другим человеком без слежки - построенная на инфраструктуре, которая не может её предать."; /* No comment provided by engineer. */ -"The same conditions will apply to operator **%@**." = "Те же условия будут действовать для оператора **%s**."; +"The same conditions will apply to operator **%@**." = "Те же условия будут действовать для оператора **%@**."; /* No comment provided by engineer. */ "The second preset operator in the app!" = "Второй оператор серверов в приложении!"; @@ -6014,6 +6291,18 @@ server test failure */ /* No comment provided by engineer. */ "The servers for new files of your current chat profile **%@**." = "Серверы для новых файлов Вашего текущего профиля **%@**."; +/* alert message */ +"The SimpleX name @%@ is registered without SimpleX address. Add your SimpleX address to the name via the registration page." = "SimpleX имя @%@ зарегистрировано без SimpleX адреса. Добавьте Ваш SimpleX адрес к имени на странице регистрации."; + +/* alert message */ +"The SimpleX name #%@ is registered without channel link. Add channel link to the name via the registration page." = "SimpleX имя #%@ зарегистрировано без ссылки канала. Добавьте ссылку канала к имени на странице регистрации."; + +/* No comment provided by engineer. */ +"The SimpleX name %@ is registered, but it has no valid link." = "SimpleX имя %@ зарегистрировано, но не имеет действительной ссылки."; + +/* No comment provided by engineer. */ +"The SimpleX name %@ is registered, but not added to profile. Please add it to your address or channel profile, if you are the owner." = "SimpleX имя %@ зарегистрировано, но не добавлено в профиль. Пожалуйста, добавьте его в профиль Вашего адреса или канала, если Вы владелец."; + /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Вставленный текст не является SimpleX-ссылкой."; @@ -6050,6 +6339,9 @@ server test failure */ /* No comment provided by engineer. */ "This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost." = "Это действие нельзя отменить - Ваш профиль, контакты, сообщения и файлы будут безвозвратно утеряны."; +/* badge alert */ +"This badge could not be verified and may not be genuine." = "Не удалось проверить подлинность этого значка. Возможно, он не является подлинным."; + /* E2EE info chat item */ "This chat is protected by end-to-end encryption." = "Чат защищён сквозным шифрованием."; @@ -6071,9 +6363,16 @@ server test failure */ /* No comment provided by engineer. */ "This group no longer exists." = "Эта группа больше не существует."; +/* alert message +alert subtitle */ +"This group requires a newer version of the app. Please update the app to join." = "Эта группа требует более новой версии приложения. Пожалуйста, обновите приложение, чтобы вступить."; + /* alert message */ "This is a chat relay address, it cannot be used to connect." = "Это адрес чат-релея, с ним нельзя соединиться."; +/* alert message */ +"This is the last active relay. Removing it will prevent message delivery to subscribers." = "Это последний активный релей. После его удаления доставка сообщений подписчикам будет невозможна."; + /* new chat action */ "This is your link for channel %@!" = "Это ваша ссылка на канал %@!"; @@ -6092,6 +6391,9 @@ server test failure */ /* No comment provided by engineer. */ "This setting is for your current profile **%@**." = "Эта настройка применяется к Вашему текущему профилю чата **%@**."; +/* No comment provided by engineer. */ +"This SimpleX name is not registered. Please check the name." = "Это SimpleX имя не зарегистрировано. Пожалуйста, проверьте имя."; + /* No comment provided by engineer. */ "Time to disappear is set only for new contacts." = "Время удаления устанавливается только для новых контактов."; @@ -6140,6 +6442,9 @@ server test failure */ /* No comment provided by engineer. */ "To record voice message please grant permission to use Microphone." = "Для записи голосового сообщения, пожалуйста разрешите доступ к микрофону."; +/* No comment provided by engineer. */ +"To resolve names" = "Для разрешения имён"; + /* No comment provided by engineer. */ "To reveal your hidden profile, enter a full password into a search field in **Your chat profiles** page." = "Чтобы показать Ваш скрытый профиль, введите его пароль в поле поиска на странице **Ваши профили чата**."; @@ -6161,6 +6466,9 @@ server test failure */ /* No comment provided by engineer. */ "To verify end-to-end encryption with your contact compare (or scan) the code on your devices." = "Чтобы подтвердить безопасность сквозного шифрования с Вашим контактом сравните (или сканируйте) код на ваших устройствах."; +/* No comment provided by engineer. */ +"To verify keys with this subscriber, compare (or scan) the code on your devices." = "Чтобы подтвердить ключи с этим подписчиком, сравните (или сканируйте) код на ваших устройствах."; + /* No comment provided by engineer. */ "Toggle incognito when connecting." = "Установите режим Инкогнито при соединении."; @@ -6218,6 +6526,9 @@ server test failure */ /* rcv group event chat item */ "unblocked %@" = "%@ разблокирован"; +/* No comment provided by engineer. */ +"Unconfirmed name" = "Неподтверждённое имя"; + /* No comment provided by engineer. */ "Undelivered messages" = "Недоставленные сообщения"; @@ -6287,6 +6598,9 @@ server test failure */ /* conn error description */ "Unsupported connection link" = "Ссылка не поддерживается"; +/* badge alert title */ +"Unverified badge" = "Неподтверждённый значок"; + /* No comment provided by engineer. */ "Up to 100 last messages are sent to new members." = "До 100 последних сообщений отправляются новым членам."; @@ -6435,6 +6749,9 @@ alert title */ /* No comment provided by engineer. */ "Use web port" = "Использовать веб-порт"; +/* No comment provided by engineer. */ +"Used chat relays do not support webpages." = "Используемые чат-релеи не поддерживают веб-страницы."; + /* No comment provided by engineer. */ "User selection" = "Выбор пользователя"; @@ -6465,12 +6782,18 @@ alert title */ /* No comment provided by engineer. */ "Verify database passphrase" = "Проверка пароля базы данных"; +/* No comment provided by engineer. */ +"Verify name" = "Проверить имя"; + /* No comment provided by engineer. */ "Verify passphrase" = "Проверить пароль"; /* No comment provided by engineer. */ "Verify security code" = "Подтвердить код безопасности"; +/* No comment provided by engineer. */ +"Verify SimpleX names" = "Проверять SimpleX имена"; + /* relay hostname */ "via %@" = "через %@"; @@ -6588,6 +6911,12 @@ alert title */ /* No comment provided by engineer. */ "We made connecting simpler for new users." = "Мы упростили подключение для новых пользователей."; +/* No comment provided by engineer. */ +"Webpage code" = "Код веб-страницы"; + +/* alert message */ +"Webpage settings were changed. If you save, the updated settings will be sent to subscribers." = "Настройки веб-страницы были изменены. Если Вы сохраните их, обновлённые настройки будут отправлены подписчикам."; + /* No comment provided by engineer. */ "WebRTC ICE servers" = "WebRTC ICE-серверы"; @@ -6747,6 +7076,9 @@ alert title */ /* No comment provided by engineer. */ "You can enable later via Settings" = "Вы можете включить их позже в Настройках"; +/* No comment provided by engineer. */ +"You can enable them later via app Your privacy settings." = "Вы можете включить их позже в настройках Конфиденциальности."; + /* No comment provided by engineer. */ "You can give another try." = "Вы можете попробовать ещё раз."; @@ -6783,6 +7115,9 @@ alert title */ /* No comment provided by engineer. */ "You can still view conversation with %@ in the list of chats." = "Вы по-прежнему можете просмотреть разговор с %@ в списке чатов."; +/* badge alert */ +"You can support SimpleX starting from v7 of the app." = "Вы можете поддержать SimpleX начиная с версии приложения v7."; + /* No comment provided by engineer. */ "You can turn on SimpleX Lock via Settings." = "Вы можете включить Блокировку SimpleX через Настройки."; @@ -6978,6 +7313,9 @@ alert title */ /* No comment provided by engineer. */ "Your network" = "Ваша сеть"; +/* alert message */ +"Your new channel %@ is connected to %d of %d relays.\nIf you cancel, the channel will be deleted - you can create it again." = "Ваш новый канал %1$@ подключен к %2$d из %3$d релеев.\nЕсли Вы отмените, канал будет удалён - Вы сможете создать его снова."; + /* No comment provided by engineer. */ "Your preferences" = "Ваши предпочтения"; @@ -7026,3 +7364,6 @@ alert title */ /* No comment provided by engineer. */ "Your SimpleX address" = "Ваш адрес SimpleX"; +/* No comment provided by engineer. */ +"Your SimpleX name" = "Ваше SimpleX имя"; + 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 22047e9875..9774107fcf 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml @@ -2985,7 +2985,7 @@ Der Kanal verlangt für diese Nachricht eine Signatur, welche aber fehlt. Im Kanal genutzter SimpleX-Name SimpleX-Name erhalten (BETA) - Einen Test-Namen registrieren + Wie man einen Test-Namen registriert Name entfernen SimpleX-Name speichern? Beschreibung hinzufügen @@ -2999,8 +2999,8 @@ Eine Web-Vorschau erstellen. Einfacher zu lesen. Ihre Relais verwalten. - Namen für Ihren Kanal oder Ihr Unternehmen. - SimpleX-Namen (BETA) + Öffentliche Namen für Ihren Kanal oder Ihr Unternehmen. + Öffentliche SimpleX-Namen (BETA) Datei-Server Datei-Server: %s 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 4bb171a4da..4e3ce8e810 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml @@ -152,7 +152,7 @@ Eliminar en %d seg El contácto ya existe - Error de conexión (Autenticación) + Enlace de conexión eliminado Eliminar para mí Desconectado Conectado @@ -569,7 +569,7 @@ ¡Dirección de servidor no válida! Establecer una conexión privada Comprueba tu conexión de red con %1$s e inténtalo de nuevo. - El remitente puede haber eliminado la solicitud de conexión. + El remitente ha eliminado la solicitud de conexión. La huella en la dirección del servidor no coincide con el certificado. Responder Guardar contraseña en Keystore @@ -692,7 +692,7 @@ Guardar y notificar contacto ¿Guardar preferencias\? Guardar y notificar grupo - A menos que tu contacto haya eliminado la conexión o el enlace se haya usado, podría ser un error. Por favor, notifícalo. \nPara conectarte pide a tu contacto que cree otro enlace y comprueba la conexión de red. + Tu contacto ha eliminado el enlace, o era un enlace de un solo uso que ya se ha usado.\nPara conectarte pide a tu contacto que cree otro enlace. La aplicación recoge nuevos mensajes periódicamente lo que consume un pequeño porcentaje de batería al día. La aplicación no usa notificaciones push por tanto los datos de tu dispositivo no se envían a los servidores push. Bloqueo SimpleX Desbloquear @@ -2906,8 +2906,8 @@ Firmado Firmado y verificado Firmar mensajes - Se requieren mensajes firmados. - No se requieren mensajes firmados. + Requerir la firma de mensajes. + No requerir la firma de mensajes. Los mensajes firmados son obligatorios. Los mensajes firmados no son obligatorios. Mostrar firma @@ -2915,11 +2915,20 @@ Falta la firma El canal requiere que el mensaje esté firmado, pero falta la firma. Nombre SimpleX del canal - Registrar nombre para pruebas + Cómo registrar un nombre de prueba Añadir descripción Descripción Editar descripción Introduce descripción (opcional) Error compartiendo dirección - Para verificar la clave con el suscriptor, compara (o escanea) el código en tu dispositivo. + Para verificar las claves con este suscriptor, compara (o escanea) el código en ambos dispositivos. + Añade colaboradores. + Canales mejorados 📢 + Crea previsualizaciones web. + Fácil de leer. + Servidores de archivos + Servidores de archivos: %s + Gestiona tus servidores. + Nombres públicos para tu canal o negocio. + Nombres públicos SimpleX (BETA) diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml index 0a76f6d256..f9e627b21a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml @@ -2895,8 +2895,8 @@ Előnézet készítése a weboldalakhoz. Könnyebb olvashatóság. Saját átjátszók kezelése. - Nevek a csatornákhoz vagy az üzleti profilokhoz. - SimpleX-nevek (béta) + Nyilvános nevek a csatornákhoz vagy az üzleti profilokhoz. + Nyilvános SimpleX-nevek (béta) Fájlkiszolgálók Fájlkiszolgálók: %s 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 b9a1946569..9fad882019 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml @@ -2929,8 +2929,8 @@ Crea un\'anteprima web. Lettura più facile. Gestisci i tuoi relay. - Nomi per il tuo canale o per il lavoro. - Nomi SimpleX (BETA) + Nomi pubblici per il tuo canale o per il lavoro. + Nomi pubblici SimpleX (BETA) Aggiungi collaboratori. Server di file Server di file: %s 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 5c3cb6c399..dae2a494dc 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -1670,7 +1670,6 @@ Внутренняя ошибка Очистить личные заметки? Новый чат - Новое сообщение Или отсканируйте QR-код Вы можете увидеть ссылку-приглашение снова открыв соединение. Показывать медленные вызовы API @@ -2915,4 +2914,96 @@ Релеи отсутствуют Релеи не выбраны SimpleX - %d непрочитанных сообщений + Добавить соавторов. + Добавить описание + Улучшенные каналы 📢 + SimpleX имя канала + Соединиться с %s + Создайте веб-страницу, чтобы показывать предпросмотр Вашего канала посетителям до подписки. Хостите её сами или используйте любой статический хостинг. + Создать веб-предпросмотр. + Описание + Не требовать подпись сообщений. + Легче для чтения. + Редактировать описание + Введите описание (необязательно) + Введите адрес страницы + Ошибка добавления релеев + Ошибка удаления сообщения + Ошибка сохранения имени + Ошибка отправки адреса + Серверы файлов + Серверы файлов: %s + Из истории + Зарегистрировать SimpleX имя (BETA) + Веб-страница группы + Помощь и поддержка + Как зарегистрировать тестовое имя + https:// + Если Вы выберете Закрыть, сообщения не будут доставляться.\nВы можете изменить это позже в настройках Интерфейса. + Адрес будет показан подписчикам и разрешит загрузку предпросмотра. + Вступить в канал %s + Неподдерживаемое имя канала + Неподдерживаемое имя контакта + Пожалуйста, обновите приложение. + Ошибка SimpleX имени + Ни один из Ваших серверов не настроен для разрешения SimpleX имён. Настройте серверы или используйте ссылку для соединения. + Сервер %1$s не поддерживает разрешение имён. Настройте серверы или используйте ссылку для соединения. + Имя не найдено + Это SimpleX имя не зарегистрировано. Пожалуйста, проверьте имя. + Ошибка разрешения имени: %1$s + Нет действительной ссылки + SimpleX имя %1$s зарегистрировано, но не имеет действительной ссылки. + Неподтверждённое имя + SimpleX имя %1$s зарегистрировано, но не добавлено в профиль. Пожалуйста, добавьте его в профиль Вашего адреса или канала, если Вы владелец. + Эта группа требует более новой версии приложения. Пожалуйста, обновите приложение, чтобы вступить. + Сохранить SimpleX имя? + Удалить имя + Подписать сообщение + Подпись доказывает, что Вы — автор этого сообщения, и это нельзя будет отрицать. + Подписано + Подписано и проверено + Подпись сообщений + Требовать подпись сообщений. + Подпись сообщений обязательна. + Подпись сообщений не обязательна. + Показывать подпись + Показывать шифрование + Подпись отсутствует + Канал требует подпись сообщений, но у этого сообщения подпись отсутствует. + Проверить имя + Проверять SimpleX имена + SimpleX имя не проверено + SimpleX имя + Ваше SimpleX имя + Установить SimpleX имя + SimpleX имя %1$s зарегистрировано без ссылки канала. Добавьте ссылку канала к имени на странице регистрации. + SimpleX имя %1$s зарегистрировано без SimpleX адреса. Добавьте Ваш SimpleX адрес к имени на странице регистрации. + Позвольте людям соединяться с Вами через имя, зарегистрированное для Вашего SimpleX адреса. + Позвольте людям вступать через имя, зарегистрированное для ссылки этого канала. + Чтобы подтвердить ключи с этим подписчиком, сравните (или сканируйте) код на ваших устройствах. + Поддержать проект + Больше конфиденциальности + Код веб-страницы + Используемые чат-релеи не поддерживают веб-страницы. + Предпросмотр можно отобразить только на Вашей странице, указанной выше. + Роль будет изменена на "%s". Все в канале получат сообщение. + Для разрешения имён + Публичные SimpleX имена (BETA) + Публичные имена для Вашего канала или бизнеса. + Управлять своими релеями. + удалён + отклонён + Статус + отклонён оператором релея + Релей будет удалён из канала - это нельзя отменить! + Это последний активный релей. После его удаления доставка сообщений подписчикам будет невозможна. + Ваш новый канал %1$s подключен к %2$d из %3$d релеев.\nЕсли Вы отмените, канал будет удалён - Вы сможете создать его снова. + Нет доступных релеев + Добавлены релеи: %1$s. + Выберите релеи + Свернуть в трей? + Свернуть в трей + Показать SimpleX + Выйти из SimpleX + SimpleX 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 fa7fbe5685..9dea7a5a0a 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 @@ -2889,7 +2889,7 @@ 获得 SimpleX 名称 (测试) 不要求消息签名。 要求消息签名。 - 注册测试名 + 如何注册测试名 删除名称 要求消息签名。 保存 SimpleX 名称? @@ -2913,8 +2913,8 @@ 创建 web 预览。 更易阅读。 管理你的中继。 - 你的频道或企业的名称。 - SimpleX 名称 (测试) + 你的频道或企业的公开名称。 + SimpleX 公开名称 (测试) 文件服务器 文件服务器:%s From 7c931d08eaf0f6ef6267d31055c6ac1cccdb9207 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Tue, 28 Jul 2026 11:03:42 +0000 Subject: [PATCH 3/7] ui: show "connect to name" button starting with 5 characters; ios: show button in New chat view search (#7318) * ui: show "connect to name" button starting with 5 characters * show button in new chat view search --- .../Shared/Views/ChatList/ChatListView.swift | 83 ++++++++++++------- .../Views/NewChat/NewChatMenuButton.swift | 59 ++++++++----- .../common/views/chatlist/ChatListView.kt | 4 +- 3 files changed, 91 insertions(+), 55 deletions(-) diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 27840a07c2..b05e0696e3 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -649,7 +649,13 @@ struct ChatListSearchBar: View { // a typed name shows a row to connect to it (as on Android mobile): with the reachable toolbar it // replaces the tags above the search field; in top bar mode the tags stay and it moves below (end of VStack) if oneHandUI, let candidate = connectNameCandidate { - connectByNameRow(candidate) + ConnectByNameRow( + name: candidate, + searchText: $searchText, + connectNameCandidate: $connectNameCandidate, + searchFocussed: $searchFocussed, + dismiss: false + ) } else { ScrollView([.horizontal], showsIndicators: false) { TagsView(parentSheet: $parentSheet, searchText: $searchText) } } @@ -688,7 +694,13 @@ struct ChatListSearchBar: View { } } if !oneHandUI, let candidate = connectNameCandidate { - connectByNameRow(candidate) + ConnectByNameRow( + name: candidate, + searchText: $searchText, + connectNameCandidate: $connectNameCandidate, + searchFocussed: $searchFocussed, + dismiss: false + ) } } .onChange(of: searchFocussed) { sf in @@ -770,33 +782,6 @@ struct ChatListSearchBar: View { } } - // Row shown in place of the list tags when the search text is a SimpleX name. The @ icon marks a - // contact name, the tag icon a channel/other name; tapping hides the keyboard, connects online, and - // clears the field. - private func connectByNameRow(_ name: String) -> some View { - HStack(spacing: 4) { - Image(systemName: name.hasPrefix("@") ? "at" : "number") - .foregroundColor(theme.colors.primary) - Text(String.localizedStringWithFormat(NSLocalizedString("Connect to %@", comment: "new chat action"), name)) - .foregroundColor(theme.colors.primary) - Spacer() - } - .frame(maxWidth: .infinity, alignment: .leading) - .contentShape(Rectangle()) - .onTapGesture { - searchFocussed = false - planAndConnect( - name, - theme: theme, - dismiss: false, - cleanup: { - searchText = "" - connectNameCandidate = nil - } - ) - } - } - private func connect(_ link: String) { planAndConnect( link, @@ -812,11 +797,47 @@ struct ChatListSearchBar: View { } } +// Row shown when the search text is a SimpleX name — in place of the list tags in the chat list, below +// the search field in the new chat sheet. The @ icon marks a contact name, the tag icon a channel/other +// name; tapping hides the keyboard, connects online, and clears the field. +struct ConnectByNameRow: View { + @EnvironmentObject var theme: AppTheme + var name: String + @Binding var searchText: String + @Binding var connectNameCandidate: String? + @FocusState.Binding var searchFocussed: Bool + var dismiss: Bool + + var body: some View { + HStack(spacing: 4) { + Image(systemName: name.hasPrefix("@") ? "at" : "number") + .foregroundColor(theme.colors.primary) + Text(String.localizedStringWithFormat(NSLocalizedString("Connect to %@", comment: "new chat action"), name)) + .foregroundColor(theme.colors.primary) + Spacer() + } + .frame(maxWidth: .infinity, alignment: .leading) + .contentShape(Rectangle()) + .onTapGesture { + searchFocussed = false + planAndConnect( + name, + theme: theme, + dismiss: dismiss, + cleanup: { + searchText = "" + connectNameCandidate = nil + } + ) + } + } +} + // Default top-level part used to complete a bare name typed in the search field (search field only; // the message parser and the wire format are unchanged). private let DEFAULT_NAME_TLD = "testing" -// Shortest name that offers the button, so it is discoverable but does not flash on a single letter. -private let MIN_NAME_LENGTH = 2 +// Shortest name that offers the button, so it is discoverable but does not flash on short prefixes. +private let MIN_NAME_LENGTH = 5 private func isNameLabel(_ s: String) -> Bool { s.count >= 1 && s.count <= 63 && s.range(of: "^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$", options: .regularExpression) != nil diff --git a/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift b/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift index 4690bf82a8..416dc32308 100644 --- a/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift +++ b/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift @@ -41,6 +41,8 @@ struct NewChatSheet: View { @State private var searchText = "" @State private var searchShowingSimplexLink = false @State private var searchChatFilteredBySimplexLink: String? = nil + // when the search text is a SimpleX name, the string to connect to (with @/# preserved); nil otherwise + @State private var connectNameCandidate: String? = nil @State private var alert: SomeAlert? // Sheet height management @@ -81,15 +83,25 @@ struct NewChatSheet: View { private func viewBody(_ showArchive: Bool) -> some View { List { - HStack { + VStack(spacing: 12) { ContactsListSearchBar( searchMode: $searchMode, searchFocussed: $searchFocussed, searchText: $searchText, searchShowingSimplexLink: $searchShowingSimplexLink, - searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink + searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink, + connectNameCandidate: $connectNameCandidate ) .frame(maxWidth: .infinity) + if let candidate = connectNameCandidate { + ConnectByNameRow( + name: candidate, + searchText: $searchText, + connectNameCandidate: $connectNameCandidate, + searchFocussed: $searchFocussed, + dismiss: true + ) + } } .listRowSeparator(.hidden) .listRowBackground(Color.clear) @@ -327,6 +339,7 @@ struct ContactsListSearchBar: View { @Binding var searchText: String @Binding var searchShowingSimplexLink: Bool @Binding var searchChatFilteredBySimplexLink: String? + @Binding var connectNameCandidate: String? @State private var ignoreSearchTextChange = false @AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false @@ -381,33 +394,32 @@ struct ContactsListSearchBar: View { if ignoreSearchTextChange { ignoreSearchTextChange = false } else { - switch strConnectTarget(t.trimmingCharacters(in: .whitespaces)) { + let s = t.trimmingCharacters(in: .whitespaces) + switch strConnectTarget(s) { case let .link(text, _, linkText): searchFocussed = false ignoreSearchTextChange = true searchText = linkText searchShowingSimplexLink = true searchChatFilteredBySimplexLink = nil + connectNameCandidate = nil connect(text) - case let .name(text, _): - searchFocussed = false - planAndConnect( - text, - theme: theme, - dismiss: true, - cleanup: { - searchText = "" - searchFocussed = false + default: + // A name is resolved only when its "Connect to …" row is tapped, not on every keystroke. + // The simplex-name filter is chat-list only: this contacts/deleted view is a scoped + // subset, so a resolved chat id (channel, business, unlisted or active-only contact) + // may not be present in it. + let candidate = nameSearchCandidate(s) + connectNameCandidate = candidate + if candidate == nil { + if t != "" { + searchFocussed = true + } else { + connectProgressManager.cancelConnectProgress() } - ) - case .none: - if t != "" { - searchFocussed = true - } else { - connectProgressManager.cancelConnectProgress() + searchShowingSimplexLink = false + searchChatFilteredBySimplexLink = nil } - searchShowingSimplexLink = false - searchChatFilteredBySimplexLink = nil } } } @@ -449,7 +461,9 @@ struct DeletedChats: View { @State private var searchText = "" @State private var searchShowingSimplexLink = false @State private var searchChatFilteredBySimplexLink: String? = nil - + // deleted contacts are not connected to by name, so this candidate only stops per-keystroke resolution + @State private var connectNameCandidate: String? = nil + var body: some View { List { ContactsListSearchBar( @@ -457,7 +471,8 @@ struct DeletedChats: View { searchFocussed: $searchFocussed, searchText: $searchText, searchShowingSimplexLink: $searchShowingSimplexLink, - searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink + searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink, + connectNameCandidate: $connectNameCandidate ) .listRowSeparator(.hidden) .listRowBackground(Color.clear) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 439d1af189..77b4c40d7d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -1039,8 +1039,8 @@ private fun BoxScope.ChatList(searchText: MutableState, listStat // Default top-level part used to complete a bare name typed in the search field (search field only; // the message parser and the wire format are unchanged). private const val DEFAULT_NAME_TLD = "testing" -// Shortest name that offers the button, so it is discoverable but does not flash on a single letter. -private const val MIN_NAME_LENGTH = 2 +// Shortest name that offers the button, so it is discoverable but does not flash on short prefixes. +private const val MIN_NAME_LENGTH = 5 // Wait this long after the last keystroke before the local name search runs. internal const val NAME_SEARCH_DEBOUNCE_MS = 300L From bd298a1d4a024037226afc3f8d36c5798a022022 Mon Sep 17 00:00:00 2001 From: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:55:49 +0000 Subject: [PATCH 4/7] ios, android, desktop: fix draft in support chat appearing in group chat (#7309) Group chat and its support chats have the same chat id, so a draft saved in "chat with admins" was restored in the group chat and shown as its draft in the chat list. Include chat scope in the draft chat id. Also save the draft when support chat is closed without changing chat id - in that case KeyChangeEffect that saves drafts doesn't run. --- apps/ios/Shared/Model/ChatModel.swift | 1 + apps/ios/Shared/Views/Chat/ChatView.swift | 2 +- .../Chat/ComposeMessage/ComposeView.swift | 6 ++--- apps/ios/SimpleXChat/ChatTypes.swift | 8 ++++++ .../chat/simplex/common/model/ChatModel.kt | 7 +++++ .../simplex/common/views/chat/ChatView.kt | 2 +- .../simplex/common/views/chat/ComposeView.kt | 26 ++++++++++++++----- 7 files changed, 41 insertions(+), 11 deletions(-) diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index dedb03b5aa..e3a6ae30b9 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -429,6 +429,7 @@ final class ChatModel: ObservableObject { // audio recording and playback @Published var stopPreviousRecPlay: URL? = nil // coordinates currently playing source @Published var draft: ComposeState? + // chat id with chat scope, see draftChatId() - group chat and its support chats have the same chat id @Published var draftChatId: String? @Published var networkInfo = UserNetworkInfo(networkType: .other, online: true) // usage conditions diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 6d9043332d..bc55fc6174 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -780,7 +780,7 @@ struct ChatView: View { } updateAvailableContent() } - if chatModel.draftChatId == cInfo.id && !composeState.forwarding, + if chatModel.draftChatId == draftChatId(cInfo.id, cInfo.groupChatScope()) && !composeState.forwarding, let draft = chatModel.draft { composeState = draft } diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 734ccc083c..54f8597ffc 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -1548,7 +1548,7 @@ struct ComposeView: View { let wasForwarding = composeState.forwarding clearState(live: live) if wasForwarding, - chatModel.draftChatId == chat.chatInfo.id, + chatModel.draftChatId == draftChatId(chat.chatInfo.id, chat.chatInfo.groupChatScope()), let draft = chatModel.draft { composeState = draft } @@ -1851,12 +1851,12 @@ struct ComposeView: View { // Spec: spec/client/compose.md#saveCurrentDraft private func saveCurrentDraft() { chatModel.draft = composeState - chatModel.draftChatId = chat.id + chatModel.draftChatId = draftChatId(chat.id, chat.chatInfo.groupChatScope()) } // Spec: spec/client/compose.md#clearCurrentDraft private func clearCurrentDraft() { - if chatModel.draftChatId == chat.id { + if chatModel.draftChatId == draftChatId(chat.id, chat.chatInfo.groupChatScope()) { chatModel.draft = nil chatModel.draftChatId = nil } diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index d02bff75f8..e6940b11d4 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -2137,6 +2137,14 @@ public func sameChatScope(_ scope1: GroupChatScope, _ scope2: GroupChatScope) -> } } +public func draftChatId(_ chatId: ChatId?, _ scope: GroupChatScope?) -> ChatId? { + guard let chatId, let scope else { return chatId } + return switch scope { + case let .memberSupport(groupMemberId_): "\(chatId) support:\(groupMemberId_?.description ?? "")" + case .reports: "\(chatId) reports" + } +} + public enum GroupChatScopeInfo: Decodable, Hashable { case memberSupport(groupMember_: GroupMember?) case reports // surrogate scope used for matching new items to opened Reports "chat scope" in UI, this type is not present in backend 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 58c455840e..c9c30950ea 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 @@ -202,6 +202,7 @@ object ChatModel { val migrationState: MutableState by lazy { mutableStateOf(MigrationToDeviceState.makeMigrationState()) } var draft = mutableStateOf(null as ComposeState?) + // chat id with chat scope, see draftChatId() - group chat and its support chats have the same chat id var draftChatId = mutableStateOf(null as String?) // working with external intents or internal forwarding of chat items @@ -1259,6 +1260,12 @@ fun sameChatScope(scope1: GroupChatScope, scope2: GroupChatScope) = && scope2 is GroupChatScope.MemberSupport && scope1.groupMemberId_ == scope2.groupMemberId_ +fun draftChatId(chatId: String?, scope: GroupChatScope?): String? = + if (chatId == null || scope == null) chatId + else when (scope) { + is GroupChatScope.MemberSupport -> "$chatId support:${scope.groupMemberId_ ?: ""}" + } + @Serializable sealed class GroupChatScopeInfo { @Serializable @SerialName("memberSupport") data class MemberSupport(val groupMember_: GroupMember?) : GroupChatScopeInfo() 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 288ad41d4a..12f13a426f 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 @@ -135,7 +135,7 @@ fun ChatView( val draft = chatModel.draft.value val sharedContent = chatModel.sharedContent.value mutableStateOf( - if (chatModel.draftChatId.value == staleChatId.value && draft != null && (sharedContent !is SharedContent.Forward || sharedContent.fromChatInfo.id == staleChatId.value)) { + if (chatModel.draftChatId.value == draftChatId(staleChatId.value, chatsCtx.groupScopeInfo?.toChatScope()) && draft != null && (sharedContent !is SharedContent.Forward || sharedContent.fromChatInfo.id == staleChatId.value)) { draft } else { ComposeState(useLinkPreviews = useLinkPreviews) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt index b0dad99452..40d7927264 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt @@ -394,6 +394,8 @@ fun ComposeView( focusRequester: FocusRequester?, ) { val cancelledLinks = rememberSaveable { mutableSetOf() } + val chatScope = remember(chatsCtx) { chatsCtx.groupScopeInfo?.toChatScope() } + val scopeChatId = remember { chat.id } fun isSimplexLink(link: String): Boolean = link.startsWith("https://simplex.chat", true) || link.startsWith("http://simplex.chat", true) @@ -489,14 +491,14 @@ fun ComposeView( } fun clearPrevDraft(prevChatId: String?) { - if (chatModel.draftChatId.value == prevChatId) { + if (chatModel.draftChatId.value == draftChatId(prevChatId, chatScope)) { chatModel.draft.value = null chatModel.draftChatId.value = null } } fun clearCurrentDraft() { - if (chatModel.draftChatId.value == chat.id) { + if (chatModel.draftChatId.value == draftChatId(chat.id, chatScope)) { chatModel.draft.value = null chatModel.draftChatId.value = null } @@ -936,7 +938,7 @@ fun ComposeView( composeState.value = lastFailed } val draft = chatModel.draft.value - if (wasForwarding && chatModel.draftChatId.value == chat.chatInfo.id && forwardingFromChatId != chat.chatInfo.id && draft != null) { + if (wasForwarding && chatModel.draftChatId.value == draftChatId(chat.chatInfo.id, chatScope) && forwardingFromChatId != chat.chatInfo.id && draft != null) { composeState.value = draft } else { clearCurrentDraft() @@ -1326,10 +1328,10 @@ fun ComposeView( } if (saveLastDraft) { chatModel.draft.value = composeState.value - chatModel.draftChatId.value = prevChatId + chatModel.draftChatId.value = draftChatId(prevChatId, chatScope) } composeState.value = ComposeState(useLinkPreviews = useLinkPreviews) - } else if (chatModel.draftChatId.value == chatModel.chatId.value && chatModel.draft.value != null) { + } else if (chatModel.draftChatId.value == draftChatId(chatModel.chatId.value, chatScope) && chatModel.draft.value != null) { composeState.value = chatModel.draft.value ?: ComposeState(useLinkPreviews = useLinkPreviews) } else { clearPrevDraft(prevChatId) @@ -1359,11 +1361,23 @@ fun ComposeView( onDispose { if (chatModel.sharedContent.value is SharedContent.Forward && saveLastDraft && !composeState.value.empty) { chatModel.draft.value = composeState.value - chatModel.draftChatId.value = currentChatId.value + chatModel.draftChatId.value = draftChatId(currentChatId.value, chatScope) } } } } + // support chat is closed without changing chat id, and then `KeyChangeEffect(chatModel.chatId.value)` doesn't save the draft + DisposableEffect(Unit) { + onDispose { + val cs = composeState.value + // chat change is handled by KeyChangeEffect, unfinished voice recording should not replace the saved draft + if (chatScope == null || chatModel.chatId.value != scopeChatId || (cs.preview is ComposePreview.VoicePreview && !cs.preview.finished)) return@onDispose + if (saveLastDraft && !cs.empty) { + chatModel.draft.value = cs + chatModel.draftChatId.value = draftChatId(scopeChatId, chatScope) + } else clearPrevDraft(scopeChatId) + } + } @Composable fun SendMsgView_( From e11128ce5b0df538c57a0d0b6911de0e88fdb652 Mon Sep 17 00:00:00 2001 From: SimpleX Chat Date: Tue, 28 Jul 2026 14:39:29 +0000 Subject: [PATCH 5/7] 7.0: android 366, desktop 155, ios 345 --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 20 +++++++++---------- apps/multiplatform/gradle.properties | 8 ++++---- packages/simplex-chat-nodejs/package.json | 2 +- .../simplex-chat-nodejs/src/download-libs.js | 2 +- .../src/simplex_chat/_version.py | 4 ++-- .../flatpak/chat.simplex.simplex.metainfo.xml | 17 ++++++++++++++++ 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index ba73586836..0f7dab1eba 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -2081,7 +2081,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -2131,7 +2131,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -2173,7 +2173,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -2193,7 +2193,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -2218,7 +2218,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GCC_OPTIMIZATION_LEVEL = s; @@ -2255,7 +2255,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_CODE_COVERAGE = NO; @@ -2292,7 +2292,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2343,7 +2343,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2397,7 +2397,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -2431,7 +2431,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 344; + CURRENT_PROJECT_VERSION = 345; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; diff --git a/apps/multiplatform/gradle.properties b/apps/multiplatform/gradle.properties index 15a6f68dd0..b4a7b4319a 100644 --- a/apps/multiplatform/gradle.properties +++ b/apps/multiplatform/gradle.properties @@ -24,13 +24,13 @@ android.nonTransitiveRClass=true kotlin.mpp.androidSourceSetLayoutVersion=2 kotlin.jvm.target=11 -android.version_name=7.0-beta.6 -android.version_code=365 +android.version_name=7.0 +android.version_code=366 android.bundle=false -desktop.version_name=7.0-beta.6 -desktop.version_code=154 +desktop.version_name=7.0 +desktop.version_code=155 kotlin.version=2.1.20 gradle.plugin.version=8.7.0 diff --git a/packages/simplex-chat-nodejs/package.json b/packages/simplex-chat-nodejs/package.json index b672a78d9b..76833f70c8 100644 --- a/packages/simplex-chat-nodejs/package.json +++ b/packages/simplex-chat-nodejs/package.json @@ -1,6 +1,6 @@ { "name": "simplex-chat", - "version": "7.0.0-beta.5", + "version": "7.0.0", "main": "dist/index.js", "types": "dist/index.d.ts", "files": [ diff --git a/packages/simplex-chat-nodejs/src/download-libs.js b/packages/simplex-chat-nodejs/src/download-libs.js index 967dd836c0..e0685e0123 100644 --- a/packages/simplex-chat-nodejs/src/download-libs.js +++ b/packages/simplex-chat-nodejs/src/download-libs.js @@ -4,7 +4,7 @@ const path = require('path'); const extract = require('extract-zip'); const GITHUB_REPO = 'simplex-chat/simplex-chat-libs'; -const RELEASE_TAG = 'v7.0.0-beta.5'; +const RELEASE_TAG = 'v7.0.0'; const BACKEND = (process.env.SIMPLEX_BACKEND || process.env.npm_config_simplex_backend || 'sqlite').toLowerCase(); if (BACKEND !== 'sqlite' && BACKEND !== 'postgres') { diff --git a/packages/simplex-chat-python/src/simplex_chat/_version.py b/packages/simplex-chat-python/src/simplex_chat/_version.py index 7bc0344c03..e1cbccc2da 100644 --- a/packages/simplex-chat-python/src/simplex_chat/_version.py +++ b/packages/simplex-chat-python/src/simplex_chat/_version.py @@ -5,5 +5,5 @@ Bump both together for normal releases. For wrapper-only fixes use a PEP 440 post-release: __version__ = "6.5.2.post1", LIBS_VERSION unchanged. """ -__version__ = "7.0.0b5" # PEP 440 — read by hatchling for wheel metadata -LIBS_VERSION = "7.0.0-beta.5" # simplex-chat-libs release tag (no 'v' prefix) +__version__ = "7.0.0" # PEP 440 — read by hatchling for wheel metadata +LIBS_VERSION = "7.0.0" # simplex-chat-libs release tag (no 'v' prefix) diff --git a/scripts/flatpak/chat.simplex.simplex.metainfo.xml b/scripts/flatpak/chat.simplex.simplex.metainfo.xml index b527720e5b..e6ecc7478d 100644 --- a/scripts/flatpak/chat.simplex.simplex.metainfo.xml +++ b/scripts/flatpak/chat.simplex.simplex.metainfo.xml @@ -38,6 +38,23 @@ + + https://simplex.chat/blog/20260722-simplex-public-names.html + +

New in v7.0.

+

SimpleX public names for channels and businesses (BETA).

+

Better channels:

+
    +
  • Promote subscribers to contributors.
  • +
  • Publish your channel on your website.
  • +
  • Verify security code with contributors.
  • +
  • Wider messages, easier to read.
  • +
  • Host your own chat relays.
  • +
+

Add a longer description to your profile.

+

Simplified app settings.

+
+
https://simplex.chat/blog/20260430-simplex-channels-v6-5-consortium-crowdfunding-freedom-of-speech.html From 64bf358040dcf1d43fc3ee6cbf7042867bdf0aae Mon Sep 17 00:00:00 2001 From: Evgeny Date: Tue, 28 Jul 2026 17:51:01 +0100 Subject: [PATCH 6/7] core: fix version update on binary chunks (#7320) * core: fix version update on binary chunks * pass chat event * pass encoding * revert --------- Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com> --- src/Simplex/Chat/Library/Internal.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Simplex/Chat/Library/Internal.hs b/src/Simplex/Chat/Library/Internal.hs index 6fb002eaee..bf6dde842c 100644 --- a/src/Simplex/Chat/Library/Internal.hs +++ b/src/Simplex/Chat/Library/Internal.hs @@ -2674,7 +2674,9 @@ sendPendingGroupMessages user gInfo GroupMember {groupMemberId} conn = do saveDirectRcvMSG :: forall e. MsgEncodingI e => Connection -> MsgMeta -> ChatMessage e -> CM (Connection, RcvMessage) saveDirectRcvMSG conn@Connection {connId} agentMsgMeta chatMsg@ChatMessage {chatVRange, msgId = sharedMsgId_, chatMsgEvent} = do - conn' <- updatePeerChatVRange conn chatVRange + conn' <- case encoding @e of + SJson -> updatePeerChatVRange conn chatVRange + SBinary -> pure conn let agentMsgId = fst $ recipient agentMsgMeta brokerTs = metaBrokerTs agentMsgMeta newMsg = NewRcvMessage {chatMsgEvent, verifiedMsg = VMUnsigned chatMsg, brokerTs} From f1418f9e5529e41e5fafae9911813f9500d876b1 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 29 Jul 2026 19:06:20 +0100 Subject: [PATCH 7/7] core: drop support of chat versions older than 08/2024 (#7319) * core: drop support of chat versions older than 08/2024 * fix encoding tests * skip failing tests * rename * fix * query plans * remove unused legacy code * remove more unused * remove unused * remove unused names --------- Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com> --- bots/api/EVENTS.md | 15 -- bots/src/API/Docs/Events.hs | 1 - .../types/typescript/src/events.ts | 10 -- .../src/simplex_chat/types/_events.py | 16 +- src/Simplex/Chat/Controller.hs | 1 - src/Simplex/Chat/Library/Commands.hs | 30 ++-- src/Simplex/Chat/Library/Internal.hs | 150 +++++++----------- src/Simplex/Chat/Library/Subscriber.hs | 112 ++++--------- src/Simplex/Chat/Protocol.hs | 38 ----- src/Simplex/Chat/Store/Groups.hs | 40 ----- .../SQLite/Migrations/chat_query_plans.txt | 15 +- src/Simplex/Chat/Types.hs | 4 +- src/Simplex/Chat/View.hs | 1 - tests/ChatClient.hs | 25 +-- tests/ChatTests/Direct.hs | 6 +- tests/ChatTests/Groups.hs | 6 +- tests/ChatTests/Profiles.hs | 4 +- tests/ChatTests/Utils.hs | 6 +- tests/ProtocolTests.hs | 118 +++++++------- 19 files changed, 182 insertions(+), 416 deletions(-) diff --git a/bots/api/EVENTS.md b/bots/api/EVENTS.md index 947c60586a..794670c436 100644 --- a/bots/api/EVENTS.md +++ b/bots/api/EVENTS.md @@ -61,7 +61,6 @@ This file is generated automatically. - [ContactConnecting](#contactconnecting) - [BusinessLinkConnecting](#businesslinkconnecting) - [JoinedGroupMemberConnecting](#joinedgroupmemberconnecting) -- [SentGroupInvitation](#sentgroupinvitation) - [GroupLinkConnecting](#grouplinkconnecting) [Network connection events](#network-connection-events) @@ -701,20 +700,6 @@ Group member is announced to the group and will be connecting to bot. --- -### SentGroupInvitation - -Sent when another user joins group via bot's link. - -**Record type**: -- type: "sentGroupInvitation" -- user: [User](./TYPES.md#user) -- groupInfo: [GroupInfo](./TYPES.md#groupinfo) -- contact: [Contact](./TYPES.md#contact) -- member: [GroupMember](./TYPES.md#groupmember) - ---- - - ### GroupLinkConnecting Sent when bot joins group via another user link. diff --git a/bots/src/API/Docs/Events.hs b/bots/src/API/Docs/Events.hs index f0c9352efd..1b04ece1a7 100644 --- a/bots/src/API/Docs/Events.hs +++ b/bots/src/API/Docs/Events.hs @@ -133,7 +133,6 @@ chatEventsDocsData = ("CEvtContactConnecting", "Contact confirmed connection.\n\nSent when contact started connecting via bot's 1-time invitation link or when bot connects to another SimpleX address."), -- CONF ("CEvtBusinessLinkConnecting", "Contact confirmed connection.\n\nSent when bot connects to another business address."), -- CONF ("CEvtJoinedGroupMemberConnecting", "Group member is announced to the group and will be connecting to bot."), -- MSG - ("CEvtSentGroupInvitation", "Sent when another user joins group via bot's link."), -- INV ("CEvtGroupLinkConnecting", "Sent when bot joins group via another user link.") -- CONF ], [] diff --git a/packages/simplex-chat-client/types/typescript/src/events.ts b/packages/simplex-chat-client/types/typescript/src/events.ts index cc19305913..a3de141e97 100644 --- a/packages/simplex-chat-client/types/typescript/src/events.ts +++ b/packages/simplex-chat-client/types/typescript/src/events.ts @@ -46,7 +46,6 @@ export type ChatEvent = | CEvt.ContactConnecting | CEvt.BusinessLinkConnecting | CEvt.JoinedGroupMemberConnecting - | CEvt.SentGroupInvitation | CEvt.GroupLinkConnecting | CEvt.HostConnected | CEvt.HostDisconnected @@ -99,7 +98,6 @@ export namespace CEvt { | "contactConnecting" | "businessLinkConnecting" | "joinedGroupMemberConnecting" - | "sentGroupInvitation" | "groupLinkConnecting" | "hostConnected" | "hostDisconnected" @@ -430,14 +428,6 @@ export namespace CEvt { member: T.GroupMember } - export interface SentGroupInvitation extends Interface { - type: "sentGroupInvitation" - user: T.User - groupInfo: T.GroupInfo - contact: T.Contact - member: T.GroupMember - } - export interface GroupLinkConnecting extends Interface { type: "groupLinkConnecting" user: T.User diff --git a/packages/simplex-chat-python/src/simplex_chat/types/_events.py b/packages/simplex-chat-python/src/simplex_chat/types/_events.py index 7b7c724c92..3b293eb608 100644 --- a/packages/simplex-chat-python/src/simplex_chat/types/_events.py +++ b/packages/simplex-chat-python/src/simplex_chat/types/_events.py @@ -281,13 +281,6 @@ class JoinedGroupMemberConnecting(TypedDict): hostMember: "T.GroupMember" member: "T.GroupMember" -class SentGroupInvitation(TypedDict): - type: Literal["sentGroupInvitation"] - user: "T.User" - groupInfo: "T.GroupInfo" - contact: "T.Contact" - member: "T.GroupMember" - class GroupLinkConnecting(TypedDict): type: Literal["groupLinkConnecting"] user: "T.User" @@ -367,7 +360,6 @@ ChatEvent = ( | ContactConnecting | BusinessLinkConnecting | JoinedGroupMemberConnecting - | SentGroupInvitation | GroupLinkConnecting | HostConnected | HostDisconnected @@ -377,7 +369,7 @@ ChatEvent = ( | ChatErrors ) -ChatEvent_Tag = Literal["contactConnected", "contactUpdated", "contactDeletedByContact", "receivedContactRequest", "newMemberContactReceivedInv", "contactSndReady", "newChatItems", "chatItemReaction", "chatItemsDeleted", "chatItemUpdated", "groupChatItemsDeleted", "chatItemsStatusesUpdated", "receivedGroupInvitation", "userJoinedGroup", "groupUpdated", "joinedGroupMember", "memberRole", "deletedMember", "leftMember", "deletedMemberUser", "groupDeleted", "connectedToGroupMember", "memberAcceptedByOther", "memberBlockedForAll", "groupMemberUpdated", "groupLinkDataUpdated", "groupRelayUpdated", "rcvFileDescrReady", "rcvFileComplete", "sndFileCompleteXFTP", "rcvFileStart", "rcvFileSndCancelled", "rcvFileAccepted", "rcvFileError", "rcvFileWarning", "sndFileError", "sndFileWarning", "acceptingContactRequest", "acceptingBusinessRequest", "contactConnecting", "businessLinkConnecting", "joinedGroupMemberConnecting", "sentGroupInvitation", "groupLinkConnecting", "hostConnected", "hostDisconnected", "subscriptionStatus", "messageError", "chatError", "chatErrors"] +ChatEvent_Tag = Literal["contactConnected", "contactUpdated", "contactDeletedByContact", "receivedContactRequest", "newMemberContactReceivedInv", "contactSndReady", "newChatItems", "chatItemReaction", "chatItemsDeleted", "chatItemUpdated", "groupChatItemsDeleted", "chatItemsStatusesUpdated", "receivedGroupInvitation", "userJoinedGroup", "groupUpdated", "joinedGroupMember", "memberRole", "deletedMember", "leftMember", "deletedMemberUser", "groupDeleted", "connectedToGroupMember", "memberAcceptedByOther", "memberBlockedForAll", "groupMemberUpdated", "groupLinkDataUpdated", "groupRelayUpdated", "rcvFileDescrReady", "rcvFileComplete", "sndFileCompleteXFTP", "rcvFileStart", "rcvFileSndCancelled", "rcvFileAccepted", "rcvFileError", "rcvFileWarning", "sndFileError", "sndFileWarning", "acceptingContactRequest", "acceptingBusinessRequest", "contactConnecting", "businessLinkConnecting", "joinedGroupMemberConnecting", "groupLinkConnecting", "hostConnected", "hostDisconnected", "subscriptionStatus", "messageError", "chatError", "chatErrors"] class OnEventDecorator(Protocol): @@ -640,12 +632,6 @@ class OnEventDecorator(Protocol): Callable[["JoinedGroupMemberConnecting"], Awaitable[None]], ]: ... - @overload - def __call__(self, event: Literal["sentGroupInvitation"], /) -> Callable[ - [Callable[["SentGroupInvitation"], Awaitable[None]]], - Callable[["SentGroupInvitation"], Awaitable[None]], - ]: ... - @overload def __call__(self, event: Literal["groupLinkConnecting"], /) -> Callable[ [Callable[["GroupLinkConnecting"], Awaitable[None]]], diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index 6a80f51a1e..528c30dfdf 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -937,7 +937,6 @@ data ChatEvent | CEvtUserAcceptedGroupSent {user :: User, groupInfo :: GroupInfo, hostContact :: Maybe Contact} -- there is the same command response | CEvtGroupLinkConnecting {user :: User, groupInfo :: GroupInfo, hostMember :: GroupMember} | CEvtBusinessLinkConnecting {user :: User, groupInfo :: GroupInfo, hostMember :: GroupMember, fromContact :: Contact} - | CEvtSentGroupInvitation {user :: User, groupInfo :: GroupInfo, contact :: Contact, member :: GroupMember} -- there is the same command response | CEvtContactUpdated {user :: User, fromContact :: Contact, toContact :: Contact} | CEvtGroupMemberUpdated {user :: User, groupInfo :: GroupInfo, fromMember :: GroupMember, toMember :: GroupMember} | CEvtContactDeletedByContact {user :: User, contact :: Contact} diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index 2226f80fab..61af4e98ee 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -1667,8 +1667,8 @@ processChatCommand cxt nm = \case pure $ CRChatRelayTestResult user (Just relayProfile) (Just $ RelayTestFailure step e) lift (withAgent' $ \a -> connRequestPQSupport a PQSupportOff cReq) >>= \case Nothing -> failWithProfile RTSConnect (ChatError $ CERelayTestError "invalid connection request") - Just (agentV, _) -> do - let chatV = agentToChatVersion agentV + Just _ -> do + let chatV = initialChatVersion subMode <- chatReadVar subscriptionMode connId <- withAgent $ \a -> prepareConnectionToJoin a (aUserId user) True cReq PQSupportOff conn@Connection {connId = testCId} <- withFastStore $ \db -> @@ -3283,7 +3283,7 @@ processChatCommand cxt nm = \case unless (groupFeatureUserAllowed SGFDirectMessages g) $ throwCmdError "direct messages not allowed" case memberConn m of Just mConn@Connection {peerChatVRange} -> do - unless (maxVersion peerChatVRange >= groupDirectInvVersion) $ throwChatError CEPeerChatVRangeIncompatible + unless (maxVersion peerChatVRange >= initialChatVersion) $ throwChatError CEPeerChatVRangeIncompatible when (isJust $ memberContactId m) $ throwCmdError "member contact already exists" subMode <- chatReadVar subscriptionMode -- TODO PQ should negotitate contact connection with PQSupportOn? @@ -3727,15 +3727,15 @@ processChatCommand cxt nm = \case lift (withAgent' $ \a -> connRequestPQSupport a PQSupportOn cReq) >>= \case Nothing -> throwChatError CEInvalidConnReq -- TODO PQ the error above should be CEIncompatibleConnReqVersion, also the same API should be called in Plan - Just (agentV, pqSup') -> do - let chatV = agentToChatVersion agentV + Just (_, pqSup') -> do + let chatV = initialChatVersion withFastStore' (\db -> getConnectionEntityByConnReq db cxt user cReqs) >>= \case Nothing -> joinNewConn chatV Just (RcvDirectMsgConnection conn@Connection {connStatus, contactConnInitiated, customUserProfileId} _ct_) | connStatus == ConnNew && contactConnInitiated -> joinNewConn chatV -- own connection link | connStatus == ConnPrepared -> do -- retrying join after error localIncognitoProfile <- forM customUserProfileId $ \pId -> withFastStore $ \db -> getProfileById db userId pId - joinPreparedConn conn (fromLocalProfile <$> localIncognitoProfile) chatV + joinPreparedConn conn (fromLocalProfile <$> localIncognitoProfile) Just ent -> throwCmdError $ "connection is not RcvDirectMsgConnection: " <> show (connEntityInfo ent) where joinNewConn chatV = do @@ -3744,10 +3744,10 @@ processChatCommand cxt nm = \case connId <- withAgent $ \a -> prepareConnectionToJoin a (aUserId user) True cReq pqSup' let ccLink = CCLink cReq $ serverShortLink <$> sLnk_ conn <- withFastStore' $ \db -> createDirectConnection' db userId connId ccLink contactId_ ConnPrepared incognitoProfile subMode chatV pqSup' - joinPreparedConn conn incognitoProfile chatV - joinPreparedConn conn incognitoProfile chatV = do + joinPreparedConn conn incognitoProfile + joinPreparedConn conn incognitoProfile = do profileToSend <- presentUserBadge user incognitoProfile $ userProfileDirect user incognitoProfile Nothing True - dm <- encodeConnInfoPQ pqSup' chatV $ XInfo profileToSend + dm <- encodeConnInfoPQ pqSup' $ XInfo profileToSend sqSecured <- withAgent $ \a -> joinConnection a nm (aUserId user) (aConnId conn) True cReq dm pqSup' subMode let newStatus = if sqSecured then ConnSndReady else ConnJoined conn' <- withFastStore' $ \db -> updateConnectionStatusFromTo db conn ConnPrepared newStatus @@ -3890,14 +3890,14 @@ processChatCommand cxt nm = \case -- 2) toggle enabled, address doesn't support PQ - PQSupportOn but without compression, with version range indicating support lift (withAgent' $ \a -> connRequestPQSupport a pqSup cReq) >>= \case Nothing -> throwChatError CEInvalidConnReq - Just (agentV, _) -> do - let chatV = agentToChatVersion agentV + Just _ -> do + let chatV = initialChatVersion connId <- withAgent $ \a -> prepareConnectionToJoin a (aUserId user) True cReq pqSup pure (connId, chatV) mkXContactId :: Maybe XContactId -> CM XContactId mkXContactId = maybe (XContactId <$> drgRandomBytes 16) pure joinContact :: User -> Connection -> ConnReqContact -> Maybe Profile -> XContactId -> Maybe SharedMsgId -> Maybe (SharedMsgId, MsgContent) -> Maybe (Maybe GroupInfo) -> Maybe MemberId -> PQSupport -> CM Connection - joinContact user conn@Connection {connChatVersion = chatV} cReq incognitoProfile xContactId welcomeSharedMsgId msg_ gInfo_ relayMemberId_ pqSup = do + joinContact user conn cReq incognitoProfile xContactId welcomeSharedMsgId msg_ gInfo_ relayMemberId_ pqSup = do -- gInfo_ is Maybe (Maybe GroupInfo), where Just Nothing means "some unknown group", e.g. when joining via link without profile profileToSend <- presentUserBadge user incognitoProfile $ case gInfo_ of @@ -3907,7 +3907,7 @@ processChatCommand cxt nm = \case Just (Just gInfo) | useRelays' gInfo -> case relayMemberId_ of Just relayMemberId -> encodeXMemberConnInfo gInfo relayMemberId profileToSend Nothing -> throwChatError $ CEInternalError "relay group join without target relay memberId" - _ -> encodeConnInfoPQ pqSup chatV $ XContact profileToSend (Just xContactId) welcomeSharedMsgId msg_ + _ -> encodeConnInfoPQ pqSup $ XContact profileToSend (Just xContactId) welcomeSharedMsgId msg_ subMode <- chatReadVar subscriptionMode void $ withAgent $ \a -> joinConnection a nm (aUserId user) (aConnId conn) True cReq dm pqSup subMode withFastStore' $ \db -> updateConnectionStatusFromTo db conn ConnPrepared ConnJoined @@ -4215,8 +4215,8 @@ processChatCommand cxt nm = \case (FixedLinkData {linkConnReq = cReq}, _cData) <- getShortLinkConnReq nm user address lift (withAgent' $ \a -> connRequestPQSupport a PQSupportOff cReq) >>= \case Nothing -> throwChatError CEInvalidConnReq - Just (agentV, _) -> do - let chatV = agentToChatVersion agentV + Just _ -> do + let chatV = initialChatVersion gVar <- asks random subMode <- chatReadVar subscriptionMode connId <- withAgent $ \a -> prepareConnectionToJoin a (aUserId user) True cReq PQSupportOff diff --git a/src/Simplex/Chat/Library/Internal.hs b/src/Simplex/Chat/Library/Internal.hs index bf6dde842c..37c3b7ae7d 100644 --- a/src/Simplex/Chat/Library/Internal.hs +++ b/src/Simplex/Chat/Library/Internal.hs @@ -40,7 +40,7 @@ import Data.Foldable (foldr') import Data.Functor (($>)) import Data.Functor.Identity import Data.Int (Int64) -import Data.List (find, foldl', mapAccumL, partition) +import Data.List (foldl', mapAccumL, partition) import Data.List.NonEmpty (NonEmpty (..), (<|)) import qualified Data.List.NonEmpty as L import Data.Map.Strict (Map) @@ -96,7 +96,7 @@ import Simplex.Messaging.Compression (compressionLevel, limitDecompress') import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Crypto.File (CryptoFile (..), CryptoFileArgs (..)) import qualified Simplex.Messaging.Crypto.File as CF -import Simplex.Messaging.Crypto.Ratchet (PQEncryption (..), PQSupport (..), pattern IKPQOff, pattern PQEncOff, pattern PQEncOn, pattern PQSupportOff, pattern PQSupportOn) +import Simplex.Messaging.Crypto.Ratchet (PQEncryption (..), PQSupport (..), pattern PQEncOff, pattern PQEncOn, pattern PQSupportOff, pattern PQSupportOn) import qualified Simplex.Messaging.Crypto.Ratchet as CR import Simplex.Messaging.Encoding (smpEncode) import Simplex.Messaging.Encoding.String @@ -918,7 +918,7 @@ acceptContactRequest nm user@User {userId} UserContactRequest {agentInvitationId incognitoProfile <- forM customUserProfileId $ \pId -> withFastStore $ \db -> getProfileById db userId pId pure (ct, conn, ExistingIncognito <$> incognitoProfile) profileToSend <- presentUserBadge user incognitoProfile $ userProfileDirect user (fromIncognitoProfile <$> incognitoProfile) (Just ct) True - dm <- encodeConnInfoPQ pqSup' chatV $ XInfo profileToSend + dm <- encodeConnInfoPQ pqSup' $ XInfo profileToSend (ct,conn,) <$> withAgent (\a -> acceptContact a nm (aUserId user) (aConnId conn) True invId dm pqSup' subMode) acceptContactRequestAsync :: User -> Int64 -> Contact -> UserContactRequest -> Maybe IncognitoProfile -> CM Contact @@ -939,7 +939,7 @@ acceptContactRequestAsync Connection {connId} <- liftIO $ createAcceptedContactConn db user (Just uclId) contactId acId chatV cReqChatVRange cReqPQSup incognitoProfile subMode currentTs liftIO $ setCommandConnId db user cmdId connId getContact db cxt user contactId - agentAcceptContactAsync cmdId acId True cReqInvId (XInfo profileToSend) cReqPQSup chatV subMode + agentAcceptContactAsync cmdId acId True cReqInvId (XInfo profileToSend) cReqPQSup subMode pure ct' acceptGroupJoinRequestAsync :: User -> Int64 -> GroupInfo -> InvitationId -> VersionRangeChat -> Profile -> Maybe XContactId -> Maybe MemberId -> Maybe SharedMsgId -> GroupAcceptance -> GroupMemberRole -> Maybe IncognitoProfile -> Maybe MemberKey -> Maybe GroupMember -> CM GroupMember @@ -992,7 +992,7 @@ acceptGroupJoinRequestAsync m <- withStore $ \db -> do liftIO $ createJoiningMemberConnection db user uclId (cmdId, acId) chatV cReqChatVRange groupMemberId subMode getGroupMemberById db cxt user groupMemberId - agentAcceptContactAsync cmdId acId True cReqInvId msg PQSupportOff chatV subMode + agentAcceptContactAsync cmdId acId True cReqInvId msg PQSupportOff subMode pure m acceptGroupJoinSendRejectAsync :: User -> Int64 -> GroupInfo -> InvitationId -> VersionRangeChat -> Profile -> Maybe XContactId -> GroupRejectionReason -> CM GroupMember @@ -1024,7 +1024,7 @@ acceptGroupJoinSendRejectAsync m <- withStore $ \db -> do liftIO $ createJoiningMemberConnection db user uclId (cmdId, acId) chatV cReqChatVRange groupMemberId subMode getGroupMemberById db cxt user groupMemberId - agentAcceptContactAsync cmdId acId False cReqInvId msg PQSupportOff chatV subMode + agentAcceptContactAsync cmdId acId False cReqInvId msg PQSupportOff subMode pure m acceptBusinessJoinRequestAsync :: User -> Int64 -> GroupInfo -> GroupMember -> UserContactRequest -> CM (GroupInfo, GroupMember) @@ -1058,7 +1058,7 @@ acceptBusinessJoinRequestAsync withStore' $ \db -> do forM_ xContactId $ \xcId -> setBusinessChatAcceptedXContactId db gInfo xcId createJoiningMemberConnection db user uclId (cmdId, acId) chatV cReqChatVRange groupMemberId subMode - agentAcceptContactAsync cmdId acId True cReqInvId msg PQSupportOff chatV subMode + agentAcceptContactAsync cmdId acId True cReqInvId msg PQSupportOff subMode let cd = CDGroupSnd gInfo Nothing -- TODO [short links] move to profileContactRequest? createInternalChatItem user cd (CISndGroupE2EEInfo $ e2eInfoGroup gInfo) Nothing @@ -1087,7 +1087,7 @@ acceptRelayJoinRequestAsync gInfo' <- liftIO $ updateRelayOwnStatusFromTo db gInfo RSInvited RSAccepted ownerMember' <- getGroupMemberById db cxt user groupMemberId pure (gInfo', ownerMember') - agentAcceptContactAsync cmdId acId True cReqInvId msg PQSupportOff chatV subMode + agentAcceptContactAsync cmdId acId True cReqInvId msg PQSupportOff subMode pure r rejectRelayInvitationAsync @@ -1111,7 +1111,7 @@ rejectRelayInvitationAsync user uclId cxt groupRelayInv invId reqChatVRange init (cmdId, acId) <- prepareAgentAccept user False invId PQSupportOff withStore' $ \db -> createJoiningMemberConnection db user uclId (cmdId, acId) chatV reqChatVRange groupMemberId subMode - agentAcceptContactAsync cmdId acId False invId msg PQSupportOff chatV subMode + agentAcceptContactAsync cmdId acId False invId msg PQSupportOff subMode businessGroupProfile :: Profile -> GroupPreferences -> GroupProfile businessGroupProfile Profile {displayName, fullName, shortDescr, description, image} groupPreferences = @@ -1155,7 +1155,7 @@ shouldIntroduce m vec mem = introduceMember :: User -> GroupInfo -> GroupMember -> [GroupMember] -> Maybe MsgScope -> CM () introduceMember _ _ GroupMember {activeConn = Nothing} _ _ = throwChatError $ CEInternalError "member connection not active" -introduceMember user gInfo@GroupInfo {groupId} toMember@GroupMember {activeConn = Just conn} introduceToMembers msgScope = do +introduceMember user gInfo toMember@GroupMember {activeConn = Just conn} introduceToMembers msgScope = do void . sendGroupMessage' user gInfo introduceToMembers $ XGrpMemNew (memberInfo gInfo toMember) msgScope sendIntroductions introduceToMembers where @@ -1163,13 +1163,9 @@ introduceMember user gInfo@GroupInfo {groupId} toMember@GroupMember {activeConn updateToMemberVector reMembers updateReMembersVectors reMembers shuffledReMembers <- liftIO $ shuffleMembers reMembers - if toMember `supportsVersion` batchSendVersion - then do - let events = map (memberIntroEvt gInfo) shuffledReMembers - forM_ (L.nonEmpty events) $ \events' -> - sendGroupMemberMessages user gInfo conn events' - else forM_ shuffledReMembers $ \reMember -> - void $ sendDirectMemberMessage conn (memberIntroEvt gInfo reMember) groupId + let events = map (memberIntroEvt gInfo) shuffledReMembers + forM_ (L.nonEmpty events) $ \events' -> + sendGroupMemberMessages user gInfo conn events' updateToMemberVector :: [GroupMember] -> CM () updateToMemberVector reMembers = do let relations = map (\GroupMember {indexInGroup} -> (indexInGroup, (IDReferencedIntroduced, MRIntroduced))) reMembers @@ -1315,20 +1311,19 @@ buildGroupRoster mods = take maxGroupRosterSize $ mapMaybe rosterMember mods sendHistory :: User -> GroupInfo -> GroupMember -> CM () sendHistory _ _ GroupMember {activeConn = Nothing} = throwChatError $ CEInternalError "member connection not active" -sendHistory user gInfo@GroupInfo {membership} m@GroupMember {activeConn = Just conn} = - when (m `supportsVersion` batchSendVersion) $ do - (errs, items) <- partitionEithers <$> withStore' (\db -> getGroupHistoryItems db user gInfo m 100) - (errs', fwdMsgsByItem) <- partitionEithers <$> mapM (tryAllErrors . itemForwardMsgs) items - let errors = map ChatErrorStore errs <> errs' - unless (null errors) $ toView $ CEvtChatErrors errors - -- signed items keep the author's original bytes/signature, unsigned are re-encoded; the welcome message - -- (regular groups only; never channels) is an authored element -- all batch together in order. - let fwdEls = map (uncurry encodeFwdElement) (concat fwdMsgsByItem) - welcomeEl <- welcomeElement - let (batches, dropped) = batchElements maxEncodedMsgLength (fwdEls <> maybe [] (: []) welcomeEl) - when (dropped > 0) $ toView $ CEvtChatErrors [ChatError $ CEInternalError ("sendHistory: dropped " <> show dropped <> " oversized history messages")] - forM_ batches $ \body -> - void $ withAgent $ \a -> sendMessages a [(aConnId conn, PQEncOff, MsgFlags False, VRValue Nothing body)] +sendHistory user gInfo@GroupInfo {membership} m@GroupMember {activeConn = Just conn} = do + (errs, items) <- partitionEithers <$> withStore' (\db -> getGroupHistoryItems db user gInfo m 100) + (errs', fwdMsgsByItem) <- partitionEithers <$> mapM (tryAllErrors . itemForwardMsgs) items + let errors = map ChatErrorStore errs <> errs' + unless (null errors) $ toView $ CEvtChatErrors errors + -- signed items keep the author's original bytes/signature, unsigned are re-encoded; the welcome message + -- (regular groups only; never channels) is an authored element -- all batch together in order. + let fwdEls = map (uncurry encodeFwdElement) (concat fwdMsgsByItem) + welcomeEl <- welcomeElement + let (batches, dropped) = batchElements maxEncodedMsgLength (fwdEls <> maybe [] (: []) welcomeEl) + when (dropped > 0) $ toView $ CEvtChatErrors [ChatError $ CEInternalError ("sendHistory: dropped " <> show dropped <> " oversized history messages")] + forM_ batches $ \body -> + void $ withAgent $ \a -> sendMessages a [(aConnId conn, PQEncOff, MsgFlags False, VRValue Nothing body)] where welcomeElement :: CM (Maybe ByteString) welcomeElement = case descrEvent_ of @@ -1347,10 +1342,9 @@ sendHistory user gInfo@GroupInfo {membership} m@GroupMember {activeConn = Just c -- in channels sendHistory runs on the relay, which cannot author XMsgNew (GRRelay < GRObserver); -- the welcome message reaches new members via the channel link data instead | useRelays' gInfo = Nothing - | m `supportsVersion` groupHistoryIncludeWelcomeVersion = do + | otherwise = do let GroupInfo {groupProfile = GroupProfile {description}} = gInfo fmap (\descr -> XMsgNew $ mcSimple (MCText descr)) description - | otherwise = Nothing itemForwardMsgs :: (CChatItem 'CTGroup, (Maybe SignedMsg, Maybe GroupMemberId)) -> CM [(GrpMsgForward, VerifiedMsg 'Json)] itemForwardMsgs (cci, (signedMsg_, signedByGMId_)) = case cci of (CChatItem SMDRcv ci@ChatItem {content = CIRcvMsgContent mc, file}) @@ -1714,7 +1708,7 @@ updatePeerChatVRange conn@Connection {connId, connChatVersion = v, peerChatVRang pure conn {connChatVersion = v', peerChatVRange = msgVRange} else pure conn -- TODO v6.0 remove/review: for contacts only version upgrade should trigger enabling PQ support/encryption - if connType == ConnContact && v' >= pqEncryptionCompressionVersion && (pqSupport /= PQSupportOn || pqEncryption /= PQEncOn) + if connType == ConnContact && (pqSupport /= PQSupportOn || pqEncryption /= PQEncOn) then do withStore' $ \db -> updateConnSupportPQ db connId PQSupportOn PQEncOn pure conn' {pqSupport = PQSupportOn, pqEncryption = PQEncOn} @@ -2118,14 +2112,6 @@ deleteSupportChatIfExists db user gInfo m = do sendDirectContactMessages :: MsgEncodingI e => User -> Contact -> NonEmpty (ChatMsgEvent e) -> CM [Either ChatError SndMessage] sendDirectContactMessages user ct events = do - Connection {connChatVersion = v} <- liftEither $ contactSendConn_ ct - if v >= batchSend2Version - then sendDirectContactMessages' user ct events - else forM (L.toList events) $ \evt -> - (Right . fst <$> sendDirectContactMessage user ct evt) `catchAllErrors` \e -> pure (Left e) - -sendDirectContactMessages' :: MsgEncodingI e => User -> Contact -> NonEmpty (ChatMsgEvent e) -> CM [Either ChatError SndMessage] -sendDirectContactMessages' user ct events = do conn@Connection {connId} <- liftEither $ contactSendConn_ ct let idsEvts = L.map (ConnectionId connId,Nothing,) events msgFlags = MsgFlags {notification = any (hasNotification . toCMEventTag) events} @@ -2261,17 +2247,15 @@ batchSndMessagesJSON :: BatchMode -> NonEmpty (Either ChatError SndMessage) -> [ batchSndMessagesJSON mode = batchMessages mode maxEncodedMsgLength . L.toList encodeConnInfo :: MsgEncodingI e => ChatMsgEvent e -> CM ByteString -encodeConnInfo chatMsgEvent = do - cxt <- chatStoreCxt - encodeConnInfoPQ PQSupportOff (maxVersion (vr cxt)) chatMsgEvent +encodeConnInfo = encodeConnInfoPQ PQSupportOff -encodeConnInfoPQ :: MsgEncodingI e => PQSupport -> VersionChat -> ChatMsgEvent e -> CM ByteString -encodeConnInfoPQ pqSup v chatMsgEvent = do +encodeConnInfoPQ :: MsgEncodingI e => PQSupport -> ChatMsgEvent e -> CM ByteString +encodeConnInfoPQ pqSup chatMsgEvent = do cxt <- chatStoreCxt let info = ChatMessage {chatVRange = vr cxt, msgId = Nothing, chatMsgEvent} case encodeChatMessage maxEncodedInfoLength info of ECMEncoded connInfo -> case pqSup of - PQSupportOn | v >= pqEncryptionCompressionVersion && B.length connInfo > maxCompressedInfoLength -> do + PQSupportOn | B.length connInfo > maxCompressedInfoLength -> do let connInfo' = compressedBatchMsgBody_ connInfo when (B.length connInfo' > maxCompressedInfoLength) $ throwChatError $ CEException "large compressed info" pure connInfo' @@ -2326,7 +2310,7 @@ deliverMessagesB msgReqs = do lift . withStoreBatch $ \db -> L.map (bindRight $ createDelivery db) sent where connSupportsPQ = \case - Right (Connection {pqSupport = PQSupportOn, connChatVersion = v}, _, _) -> v >= pqEncryptionCompressionVersion + Right (Connection {pqSupport = PQSupportOn}, _, _) -> True _ -> False compressBodies = forME msgReqs $ \(conn, msgFlags, (mbr, msgIds)) -> runExceptT $ do @@ -2477,10 +2461,9 @@ sendGroupProfileUpdate user gInfo scope asGroup members = (Nothing, Just _) -> True _ -> False sendProfileUpdate = do - let members' = filter (`supportsVersion` memberProfileUpdateVersion) members -- shouldSendProfileUpdate excludes incognito membership, so the badge is presented profileUpdate <- presentUserBadge user Nothing $ redactedMemberProfile gInfo (membership gInfo) $ fromLocalProfile p - void $ sendGroupMessage' user gInfo members' $ XInfo profileUpdate + void $ sendGroupMessage' user gInfo members $ XInfo profileUpdate currentTs <- liftIO getCurrentTime withStore' $ \db -> updateUserMemberProfileSentAt db user gInfo currentTs @@ -2499,12 +2482,12 @@ sendGroupSignedMessages_ gInfo@GroupInfo {groupId} recipientMembers signedEvents sndMsgs_ <- lift $ createSndMessages idsEvts recipientMembers' <- liftIO $ shuffleMembers recipientMembers let msgFlags = MsgFlags {notification = any (hasNotification . toCMEventTag) events} - (toSendSeparate, toSendBatched, toPending, forwarded, _, dups) = - foldr' (addMember recipientMembers') ([], [], [], [], S.empty, 0 :: Int) recipientMembers' + (toSend, toPending, forwarded, _, dups) = + foldr' (addMember recipientMembers') ([], [], [], S.empty, 0 :: Int) recipientMembers' when (dups /= 0) $ logError $ "sendGroupMessages_: " <> tshow dups <> " duplicate members" -- TODO PQ either somehow ensure that group members connections cannot have pqSupport/pqEncryption or pass Off's here -- Deliver to toSend members - let (sendToMemIds, msgReqs) = prepareMsgReqs msgFlags sndMsgs_ toSendSeparate toSendBatched + let (sendToMemIds, msgReqs) = prepareMsgReqs msgFlags sndMsgs_ toSend delivered <- maybe (pure []) (fmap L.toList . deliverMessagesB) $ L.nonEmpty msgReqs when (length delivered /= length sendToMemIds) $ logError "sendGroupMessages_: sendToMemIds and delivered length mismatch" -- Save as pending for toPending members @@ -2524,29 +2507,24 @@ sendGroupSignedMessages_ gInfo@GroupInfo {groupId} recipientMembers signedEvents liftM2 (<>) (shuffle adminMs) (shuffle otherMs) where isAdmin GroupMember {memberRole} = memberRole >= GRAdmin - addMember members m acc@(toSendSeparate, toSendBatched, pending, forwarded, !mIds, !dups) = + addMember members m acc@(toSend, pending, forwarded, !mIds, !dups) = case memberSendAction gInfo events members m of Just a - | mId `S.member` mIds -> (toSendSeparate, toSendBatched, pending, forwarded, mIds, dups + 1) + | mId `S.member` mIds -> (toSend, pending, forwarded, mIds, dups + 1) | otherwise -> case a of - MSASend conn -> ((m, conn) : toSendSeparate, toSendBatched, pending, forwarded, mIds', dups) - MSASendBatched conn -> (toSendSeparate, (m, conn) : toSendBatched, pending, forwarded, mIds', dups) - MSAPending -> (toSendSeparate, toSendBatched, m : pending, forwarded, mIds', dups) - MSAForwarded -> (toSendSeparate, toSendBatched, pending, m : forwarded, mIds', dups) + MSASend conn -> ((m, conn) : toSend, pending, forwarded, mIds', dups) + MSAPending -> (toSend, m : pending, forwarded, mIds', dups) + MSAForwarded -> (toSend, pending, m : forwarded, mIds', dups) Nothing -> acc where mId = groupMemberId' m mIds' = S.insert mId mIds - prepareMsgReqs :: MsgFlags -> NonEmpty (Either ChatError SndMessage) -> [(GroupMember, Connection)] -> [(GroupMember, Connection)] -> ([GroupMemberId], [Either ChatError ChatMsgReq]) - prepareMsgReqs msgFlags msgs toSendSeparate toSendBatched = do + prepareMsgReqs :: MsgFlags -> NonEmpty (Either ChatError SndMessage) -> [(GroupMember, Connection)] -> ([GroupMemberId], [Either ChatError ChatMsgReq]) + prepareMsgReqs msgFlags msgs toSend = do let mode = if useRelays' gInfo then BMBinary else BMJson batched_ = batchSndMessagesJSON mode msgs case L.nonEmpty batched_ of - Just batched' -> do - let lenMsgs = length msgs - (memsSep, mreqsSep) = foldMembers lenMsgs sndMessageMBR msgs toSendSeparate - (memsBtch, mreqsBtch) = foldMembers (length batched' + lenMsgs) msgBatchMBR batched' toSendBatched - (memsSep <> memsBtch, mreqsSep <> mreqsBtch) + Just batched' -> foldMembers (length batched' + length msgs) msgBatchMBR batched' toSend Nothing -> ([], []) where foldMembers :: forall a. Int -> (Maybe Int -> Int -> a -> (ValueOrRef MsgBody, [MessageId])) -> NonEmpty (Either ChatError a) -> [(GroupMember, Connection)] -> ([GroupMemberId], [Either ChatError ChatMsgReq]) @@ -2561,8 +2539,6 @@ sendGroupSignedMessages_ gInfo@GroupInfo {groupId} recipientMembers signedEvents addBody mb (i, (memIds, reqs)) = let req = (conn,msgFlags,) . mkMb memIdx_ i <$> mb in (i - 1, (groupMemberId : memIds, req : reqs)) - sndMessageMBR :: Maybe Int -> Int -> SndMessage -> (ValueOrRef MsgBody, [MessageId]) - sndMessageMBR memIdx_ i SndMessage {msgId, msgBody} = (vrValue_ memIdx_ i msgBody, [msgId]) msgBatchMBR :: Maybe Int -> Int -> MsgBatch -> (ValueOrRef MsgBody, [MessageId]) msgBatchMBR memIdx_ i (MsgBatch batchBody sndMsgs) = (vrValue_ memIdx_ i batchBody, map (\SndMessage {msgId} -> msgId) sndMsgs) vrValue_ memIdx_ i v = case memIdx_ of @@ -2583,31 +2559,26 @@ sendGroupSignedMessages_ gInfo@GroupInfo {groupId} recipientMembers signedEvents createPendingMsg db (groupMemberId, msgId) = createPendingGroupMessage db groupMemberId msgId $> Right () -data MemberSendAction = MSASend Connection | MSASendBatched Connection | MSAPending | MSAForwarded +data MemberSendAction = MSASend Connection | MSAPending | MSAForwarded memberSendAction :: GroupInfo -> NonEmpty (ChatMsgEvent e) -> [GroupMember] -> GroupMember -> Maybe MemberSendAction -memberSendAction gInfo@GroupInfo {membership} events members m@GroupMember {memberRole, memberStatus} +memberSendAction gInfo@GroupInfo {membership} events members m@GroupMember {memberStatus} -- groups with relays require newer version - we don't need to check member version for batching and forwarding support | useRelays' gInfo = if -- if user is chat relay, send to all non chat relay members - | isRelay membership && not (isRelay m) -> MSASendBatched . snd <$> readyMemberConn m + | isRelay membership && not (isRelay m) -> MSASend . snd <$> readyMemberConn m -- if user is not chat relay, send only to chat relays - | not (isRelay membership) && isRelay m -> MSASendBatched . snd <$> readyMemberConn m + | not (isRelay membership) && isRelay m -> MSASend . snd <$> readyMemberConn m | otherwise -> Nothing -- TODO [relays] MSAForwarded to create GSSForwarded snd statuses? | otherwise = case memberConn m of Nothing -> pendingOrForwarded Just conn@Connection {connStatus} | connDisabled conn || connStatus == ConnDeleted || isConnFailed connStatus || memberStatus == GSMemRejected -> Nothing | connInactive conn -> Just MSAPending - | connStatus == ConnSndReady || connStatus == ConnReady -> sendBatchedOrSeparate conn + | connStatus == ConnSndReady || connStatus == ConnReady -> Just (MSASend conn) | otherwise -> pendingOrForwarded where - sendBatchedOrSeparate conn - -- admin doesn't support batch forwarding - send messages separately so that admin can forward one by one - | memberRole >= GRAdmin && not (m `supportsVersion` batchSend2Version) = Just (MSASend conn) - -- either member is not admin, or admin supports batched forwarding - | otherwise = Just (MSASendBatched conn) pendingOrForwarded = case memberCategory m of GCUserMember -> Nothing -- shouldn't happen GCInviteeMember -> Just MSAPending @@ -2616,18 +2587,14 @@ memberSendAction gInfo@GroupInfo {membership} events members m@GroupMember {memb GCPostMember -> forwardSupportedOrPending (invitedByGroupMemberId m) where forwardSupportedOrPending invitingMemberId_ - | membersSupport && all isForwardedGroupMsg events = Just MSAForwarded + | hasInvitingMember && all isForwardedGroupMsg events = Just MSAForwarded | any isXGrpMsgForward events = Nothing | otherwise = Just MSAPending where - membersSupport = - m `supportsVersion` groupForwardVersion && invitingMemberSupportsForward - invitingMemberSupportsForward = case invitingMemberId_ of + hasInvitingMember = case invitingMemberId_ of Just invMemberId -> -- can be optimized for large groups by replacing [GroupMember] with Map GroupMemberId GroupMember - case find (\m' -> groupMemberId' m' == invMemberId) members of - Just invitingMember -> invitingMember `supportsVersion` groupForwardVersion - Nothing -> False + any (\m' -> groupMemberId' m' == invMemberId) members Nothing -> False isXGrpMsgForward event = case event of XGrpMsgForward {} -> True @@ -2652,7 +2619,6 @@ sendGroupMemberMessage gInfo@GroupInfo {groupId} m@GroupMember {groupMemberId} c messageMember :: SndMessage -> CM () messageMember SndMessage {msgId, msgBody} = forM_ (memberSendAction gInfo (chatMsgEvent :| []) [m] m) $ \case MSASend conn -> void $ deliverMessage conn (toCMEventTag chatMsgEvent) msgBody msgId - MSASendBatched conn -> void $ deliverMessage conn (toCMEventTag chatMsgEvent) msgBody msgId MSAPending -> withStore' $ \db -> createPendingGroupMessage db groupMemberId msgId MSAForwarded -> pure () @@ -2874,9 +2840,9 @@ joinAgentConnectionAsync cmdId updateConn connId enableNtfs cReqUri cInfo subMod withAgent $ \a -> joinConnectionAsync a (aCorrId cmdId) updateConn connId enableNtfs cReqUri cInfo PQSupportOff subMode allowAgentConnectionAsync :: MsgEncodingI e => User -> Connection -> ConfirmationId -> ChatMsgEvent e -> CM () -allowAgentConnectionAsync user conn@Connection {connId, pqSupport, connChatVersion} confId msg = do +allowAgentConnectionAsync user conn@Connection {connId, pqSupport} confId msg = do cmdId <- withStore' $ \db -> createCommand db user (Just connId) CFAllowConn - dm <- encodeConnInfoPQ pqSupport connChatVersion msg + dm <- encodeConnInfoPQ pqSupport msg withAgent $ \a -> allowConnectionAsync a (aCorrId cmdId) (aConnId conn) confId dm withStore' $ \db -> updateConnectionStatus db conn ConnAccepted @@ -2886,9 +2852,9 @@ prepareAgentAccept user enableNtfs invId pqSup = do connId <- withAgent $ \a -> prepareConnectionToAccept a (aUserId user) enableNtfs invId pqSup pure (cmdId, connId) -agentAcceptContactAsync :: MsgEncodingI e => CommandId -> ConnId -> Bool -> InvitationId -> ChatMsgEvent e -> PQSupport -> VersionChat -> SubscriptionMode -> CM () -agentAcceptContactAsync cmdId connId enableNtfs invId msg pqSup chatV subMode = do - dm <- encodeConnInfoPQ pqSup chatV msg +agentAcceptContactAsync :: MsgEncodingI e => CommandId -> ConnId -> Bool -> InvitationId -> ChatMsgEvent e -> PQSupport -> SubscriptionMode -> CM () +agentAcceptContactAsync cmdId connId enableNtfs invId msg pqSup subMode = do + dm <- encodeConnInfoPQ pqSup msg withAgent $ \a -> acceptContactAsync a (aCorrId cmdId) connId enableNtfs invId dm pqSup subMode deleteAgentConnectionAsync :: ConnId -> CM () diff --git a/src/Simplex/Chat/Library/Subscriber.hs b/src/Simplex/Chat/Library/Subscriber.hs index a65bed75a0..7b37fe8a68 100644 --- a/src/Simplex/Chat/Library/Subscriber.hs +++ b/src/Simplex/Chat/Library/Subscriber.hs @@ -439,7 +439,7 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = when (pq /= pq') $ messageWarning "processINFOpqSupport: unexpected pqSupport change" processDirectMessage :: AEvent e -> ConnectionEntity -> Connection -> Maybe Contact -> CM () - processDirectMessage agentMsg connEntity conn@Connection {connId, connChatVersion, peerChatVRange, viaUserContactLink, customUserProfileId, connectionCode} = \case + processDirectMessage agentMsg connEntity conn@Connection {connId, viaUserContactLink, customUserProfileId, connectionCode} = \case Nothing -> case agentMsg of CONF confId pqSupport _ connInfo -> do chatRelayTests_ <- asks chatRelayTests @@ -642,19 +642,6 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = when (contactConnInitiated conn') $ do probeMatchingMembers ct' (contactConnIncognito ct') withStore' $ \db -> resetContactConnInitiated db user conn' - forM_ viaUserContactLink $ \userContactLinkId -> do - (ucl, gli_) <- withStore $ \db -> getUserContactLinkById db userId userContactLinkId - -- let UserContactLink {addressSettings = AddressSettings {autoReply}} = ucl - when (connChatVersion < batchSend2Version) $ forM_ (autoReply $ addressSettings ucl) $ \mc -> sendAutoReply ct' mc Nothing -- old versions only - -- TODO REMOVE LEGACY vvv - forM_ gli_ $ \GroupLinkInfo {groupId, memberRole = gLinkMemRole} -> do - groupInfo <- withStore $ \db -> getGroupInfo db cxt user groupId - subMode <- chatReadVar subscriptionMode - groupConnIds@(cmdId, grpConnId) <- prepareAgentCreation user CFCreateConnGrpInv True SCMInvitation - gVar <- asks random - withStore $ \db -> createNewContactMemberAsync db gVar user groupInfo ct' gLinkMemRole groupConnIds connChatVersion peerChatVRange subMode - withAgent $ \a -> createConnectionAsync a (aCorrId cmdId) grpConnId True SCMInvitation CR.IKPQOff subMode - -- TODO REMOVE LEGACY ^^^ SENT msgId proxy -> do void $ continueSending connEntity conn sentMsgDeliveryEvent conn msgId @@ -705,7 +692,7 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = when (corrId /= "") $ withCompletedCommand conn agentMsg $ \_cmdData -> when (directOrUsed ct && sqSecured) $ do toView $ CEvtContactSndReady user ct - when (connChatVersion >= batchSend2Version) $ forM_ viaUserContactLink $ \userContactLinkId -> do + forM_ viaUserContactLink $ \userContactLinkId -> do (ucl, _) <- withStore $ \db -> getUserContactLinkById db userId userContactLinkId forM_ (autoReply $ addressSettings ucl) $ \mc -> do connReq_ <- pure (contactRequestId' ct) $>>= \connReqId -> withStore' (\db -> getContactRequest' db user connReqId) @@ -740,53 +727,18 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = toView $ CEvtNewChatItems user [AChatItem SCTDirect SMDSnd (DirectChat ct) ci] processGroupMessage :: AEvent e -> ConnectionEntity -> Connection -> GroupInfo -> GroupMember -> CM () - processGroupMessage agentMsg connEntity conn@Connection {connId, connChatVersion, customUserProfileId, connectionCode} gInfo@GroupInfo {groupId, groupProfile, membership, chatSettings} m = case agentMsg of + processGroupMessage agentMsg connEntity conn@Connection {connId, customUserProfileId, connectionCode} gInfo@GroupInfo {groupId, groupProfile, membership, chatSettings} m = case agentMsg of INV (ACR _ cReq) -> withCompletedCommand conn agentMsg $ \CommandData {cmdFunction} -> case cReq of groupConnReq@(CRInvitationUri _ _) -> case cmdFunction of -- [async agent commands] XGrpMemIntro continuation on receiving INV - CFCreateConnGrpMemInv - | maxVersion (peerChatVRange conn) >= groupDirectInvVersion -> sendWithoutDirectCReq - | otherwise -> messageError "processGroupMessage INV: member chat version range incompatible" - where - sendWithoutDirectCReq = do - let GroupMember {groupMemberId, memberId} = m - hostConnId <- withStore $ \db -> do - liftIO $ setConnConnReqInv db user connId cReq - getHostConnId db user groupId - sendXGrpMemInv hostConnId Nothing XGrpMemIntroCont {groupId, groupMemberId, memberId, groupConnReq} - -- TODO REMOVE LEGACY vvv - -- [async agent commands] group link auto-accept continuation on receiving INV - CFCreateConnGrpInv -> do - (ct, groupLinkId) <- withStore $ \db -> do - ct <- getContactViaMember db cxt user m - liftIO $ setNewContactMemberConnRequest db user m cReq - liftIO $ (ct,) <$> getGroupLinkId db user gInfo - if memberRole' membership >= GRAdmin - then do - sendGrpInvitation ct m groupLinkId - toView $ CEvtSentGroupInvitation user gInfo ct m - else messageError "processGroupMessage: group link host no longer has admin role" - where - sendGrpInvitation :: Contact -> GroupMember -> Maybe GroupLinkId -> CM () - sendGrpInvitation ct GroupMember {memberId, memberRole = memRole} groupLinkId = do - let currentMemCount = fromIntegral $ currentMembers $ groupSummary gInfo - GroupMember {memberRole = userRole, memberId = userMemberId} = membership - groupInv = - GroupInvitation - { fromMember = MemberIdRole userMemberId userRole, - invitedMember = MemberIdRole memberId memRole, - connRequest = cReq, - groupProfile, - business = Nothing, - groupLinkId = groupLinkId, - groupSize = Just currentMemCount - } - (_msg, _) <- sendDirectContactMessage user ct $ XGrpInv groupInv - -- we could link chat item with sent group invitation message (_msg) - createInternalChatItem user (CDGroupRcv gInfo Nothing m) (CIRcvGroupEvent RGEInvitedViaGroupLink) Nothing - -- TODO REMOVE LEGACY ^^^ + CFCreateConnGrpMemInv -> do + let GroupMember {groupMemberId, memberId} = m + hostConnId <- withStore $ \db -> do + liftIO $ setConnConnReqInv db user connId cReq + getHostConnId db user groupId + sendXGrpMemInv hostConnId Nothing XGrpMemIntroCont {groupId, groupMemberId, memberId, groupConnReq} _ -> throwChatError $ CECommandError "unexpected cmdFunction" CRContactUri _ -> throwChatError $ CECommandError "unexpected ConnectionRequestUri type" CONF confId _pqSupport _ connInfo -> do @@ -955,7 +907,6 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = toView $ CEvtJoinedGroupMember user gInfo'' m' {memberStatus = mStatus} let Connection {viaUserContactLink} = conn when (isJust viaUserContactLink && isNothing (memberContactId m')) $ sendXGrpLinkMem gInfo'' - when (connChatVersion < batchSend2Version) $ getAutoReplyMsg >>= mapM_ (\mc -> sendGroupAutoReply mc Nothing) if useRelays' gInfo'' then do introduceInChannel cxt user gInfo'' m' @@ -1223,7 +1174,7 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = JOINED sqSecured -> -- [async agent commands] continuation on receiving JOINED when (corrId /= "") $ withCompletedCommand conn agentMsg $ \_cmdData -> - when (sqSecured && connChatVersion >= batchSend2Version) $ do + when (sqSecured) $ do mc_ <- getAutoReplyMsg forM_ mc_ $ \mc -> do connReq_ <- withStore' $ \db -> getBusinessContactRequest db user groupId @@ -1244,8 +1195,8 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = let pqSup = PQSupportOff lift (withAgent' $ \a -> connRequestPQSupport a pqSup cReq) >>= \case Nothing -> throwChatError CEInvalidConnReq - Just (agentV, _) -> do - let chatV = agentToChatVersion agentV + Just _ -> do + let chatV = initialChatVersion groupLinkId = crClientData >>= decodeJSON >>= \(CRDataGroup gli) -> Just gli cReqHash = contactCReqHash $ CRContactUri crData {crScheme = SSSimplex} -- Update connection with data derived from cReq, now available after getConnShortLinkAsync @@ -1618,15 +1569,12 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = | otherwise -> do acceptMember_ <- asks $ acceptMember . chatHooks . config maybe (pure $ Right (GAAccepted, gLinkMemRole)) (\am -> liftIO $ am gInfo gli p) acceptMember_ >>= \case - Right (acceptance, useRole) - | v < groupFastLinkJoinVersion -> - messageError "processContactConnMessage: chat version range incompatible for accepting group join request" - | otherwise -> do - let profileMode = ExistingIncognito <$> incognitoMembershipProfile gInfo - mem <- acceptGroupJoinRequestAsync user uclId gInfo invId chatVRange p xContactId_ Nothing welcomeMsgId_ acceptance useRole profileMode Nothing Nothing - (gInfo', mem', scopeInfo) <- mkGroupChatScope gInfo mem - createInternalChatItem user (CDGroupRcv gInfo' scopeInfo mem') (CIRcvGroupEvent RGEInvitedViaGroupLink) Nothing - toView $ CEvtAcceptingGroupJoinRequestMember user gInfo' mem' + Right (acceptance, useRole) -> do + let profileMode = ExistingIncognito <$> incognitoMembershipProfile gInfo + mem <- acceptGroupJoinRequestAsync user uclId gInfo invId chatVRange p xContactId_ Nothing welcomeMsgId_ acceptance useRole profileMode Nothing Nothing + (gInfo', mem', scopeInfo) <- mkGroupChatScope gInfo mem + createInternalChatItem user (CDGroupRcv gInfo' scopeInfo mem') (CIRcvGroupEvent RGEInvitedViaGroupLink) Nothing + toView $ CEvtAcceptingGroupJoinRequestMember user gInfo' mem' Left rjctReason | v < groupJoinRejectVersion -> messageWarning $ "processContactConnMessage (group " <> groupName' gInfo <> "): joining of " <> displayName <> " is blocked" @@ -1657,7 +1605,7 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = withStore $ \db -> do Connection {connId = testCId} <- createRelayTestConnection db cxt user acId ConnAccepted chatV subMode liftIO $ setCommandConnId db user cmdId testCId - agentAcceptContactAsync cmdId acId True invId msg PQSupportOff chatV subMode + agentAcceptContactAsync cmdId acId True invId msg PQSupportOff subMode | otherwise = messageError "relay test sent to non-relay link" where User {userChatRelay} = user @@ -2822,10 +2770,8 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = maybeCreateGroupDescrLocal :: GroupInfo -> GroupMember -> CM () maybeCreateGroupDescrLocal gInfo@GroupInfo {groupProfile = GroupProfile {description}} m = - unless expectHistory $ forM_ description $ \descr -> + unless (groupFeatureAllowed SGFHistory gInfo) $ forM_ description $ \descr -> createInternalChatItem user (CDGroupRcv gInfo Nothing m) (CIRcvMsgContent $ MCText descr) Nothing - where - expectHistory = groupFeatureAllowed SGFHistory gInfo && m `supportsVersion` groupHistoryIncludeWelcomeVersion processMemberProfileUpdate :: GroupInfo -> GroupMember -> Profile -> Maybe (RcvMessage, UTCTime) -> CM GroupMember processMemberProfileUpdate gInfo m@GroupMember {memberProfile = p, memberContactId} p' msgTs_ @@ -3223,16 +3169,14 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage = when (memberRole < GRAdmin) $ throwChatError (CEGroupContactRole c) case memChatVRange of Nothing -> messageError "x.grp.mem.intro: member chat version range incompatible" - Just (ChatVersionRange mcvr) - | maxVersion mcvr >= groupDirectInvVersion -> do - subMode <- chatReadVar subscriptionMode - groupConnIds@(cmdId, connId) <- prepareAgentCreation user CFCreateConnGrpMemInv (chatHasNtfs chatSettings) SCMInvitation - let chatV = maybe (minVersion (vr cxt)) (\peerVR -> vr cxt `peerConnChatVersion` fromChatVRange peerVR) memChatVRange - void $ withStore $ \db -> do - reMember <- createIntroReMember db cxt user gInfo memInfo memRestrictions - createIntroReMemberConn db user m reMember chatV memInfo groupConnIds subMode - withAgent $ \a -> createConnectionAsync a (aCorrId cmdId) connId (chatHasNtfs chatSettings) SCMInvitation CR.IKPQOff subMode - | otherwise -> messageError "x.grp.mem.intro: member chat version range incompatible" + Just _ -> do + subMode <- chatReadVar subscriptionMode + groupConnIds@(cmdId, connId) <- prepareAgentCreation user CFCreateConnGrpMemInv (chatHasNtfs chatSettings) SCMInvitation + let chatV = maybe (minVersion (vr cxt)) (\peerVR -> vr cxt `peerConnChatVersion` fromChatVRange peerVR) memChatVRange + void $ withStore $ \db -> do + reMember <- createIntroReMember db cxt user gInfo memInfo memRestrictions + createIntroReMemberConn db user m reMember chatV memInfo groupConnIds subMode + withAgent $ \a -> createConnectionAsync a (aCorrId cmdId) connId (chatHasNtfs chatSettings) SCMInvitation CR.IKPQOff subMode _ -> messageError "x.grp.mem.intro can be only sent by host member" sendXGrpMemInv :: Int64 -> Maybe ConnReqInvitation -> XGrpMemIntroCont -> CM () diff --git a/src/Simplex/Chat/Protocol.hs b/src/Simplex/Chat/Protocol.hs index 19ba3d022d..8d9c8ecfcc 100644 --- a/src/Simplex/Chat/Protocol.hs +++ b/src/Simplex/Chat/Protocol.hs @@ -56,7 +56,6 @@ import Simplex.Chat.Types import Simplex.Chat.Types.Preferences import Simplex.Chat.Types.Shared import qualified Simplex.FileTransfer.Description as FD -import Simplex.Messaging.Agent.Protocol (VersionSMPA, pqdrSMPAgentVersion) import Simplex.Messaging.Agent.Store.DB (blobFieldDecoder, fromTextField_) import Simplex.Messaging.Compression (Compressed, compress1, decompress1, decompressedSize) import qualified Simplex.Messaging.Crypto as C @@ -98,38 +97,6 @@ supportedChatVRange :: VersionRangeChat supportedChatVRange = mkVersionRange initialChatVersion currentChatVersion {-# INLINE supportedChatVRange #-} --- version range that supports skipping establishing direct connections in a group and establishing direct connection via x.grp.direct.inv -groupDirectInvVersion :: VersionChat -groupDirectInvVersion = VersionChat 2 - --- version range that supports joining group via group link without creating direct contact -groupFastLinkJoinVersion :: VersionChat -groupFastLinkJoinVersion = VersionChat 3 - --- version range that supports group forwarding -groupForwardVersion :: VersionChat -groupForwardVersion = VersionChat 4 - --- version range that supports batch sending in groups -batchSendVersion :: VersionChat -batchSendVersion = VersionChat 5 - --- version range that supports sending group welcome message in group history -groupHistoryIncludeWelcomeVersion :: VersionChat -groupHistoryIncludeWelcomeVersion = VersionChat 6 - --- version range that supports sending member profile updates to groups -memberProfileUpdateVersion :: VersionChat -memberProfileUpdateVersion = VersionChat 7 - --- version range that supports compressing messages and PQ e2e encryption -pqEncryptionCompressionVersion :: VersionChat -pqEncryptionCompressionVersion = VersionChat 8 - --- version range that supports batch sending in direct connections, and forwarding batched messages in groups -batchSend2Version :: VersionChat -batchSend2Version = VersionChat 9 - -- supports differentiating business chats when joining contact addresses businessChatsVersion :: VersionChat businessChatsVersion = VersionChat 10 @@ -167,11 +134,6 @@ relayWebCapVersion = VersionChat 18 groupRosterVersion :: VersionChat groupRosterVersion = VersionChat 19 -agentToChatVersion :: VersionSMPA -> VersionChat -agentToChatVersion v - | v < pqdrSMPAgentVersion = initialChatVersion - | otherwise = pqEncryptionCompressionVersion - data ConnectionEntity = RcvDirectMsgConnection {entityConnection :: Connection, contact :: Maybe Contact} | RcvGroupMsgConnection {entityConnection :: Connection, groupInfo :: GroupInfo, groupMember :: GroupMember} diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index d607541bda..620eb0cc7c 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -27,7 +27,6 @@ module Simplex.Chat.Store.Groups getGroupLinkConnection, deleteGroupLink, getGroupLink, - getGroupLinkId, setGroupLinkMemberRole, setGroupLinkShortLink, createNewGroup, @@ -129,13 +128,11 @@ module Simplex.Chat.Store.Groups getRelayServedGroups, getRelayPublishableGroups, getRelayInactiveGroups, - createNewContactMemberAsync, createJoiningMember, getMemberJoinRequest, createJoiningMemberConnection, createBusinessRequestGroup, getContactViaMember, - setNewContactMemberConnRequest, getMemberInvitation, createMemberConnection, createMemberConnectionAsync, @@ -354,11 +351,6 @@ getGroupLink db User {userId} gInfo@GroupInfo {groupId} = acceptMemberRole = fromMaybe GRMember mRole_ } -getGroupLinkId :: DB.Connection -> User -> GroupInfo -> IO (Maybe GroupLinkId) -getGroupLinkId db User {userId} GroupInfo {groupId} = - fmap join . maybeFirstRow fromOnly $ - DB.query db "SELECT group_link_id FROM user_contact_links WHERE user_id = ? AND group_id = ? LIMIT 1" (userId, groupId) - setGroupLinkMemberRole :: DB.Connection -> User -> GroupLink -> GroupMemberRole -> IO GroupLink setGroupLinkMemberRole db User {userId} gLnk@GroupLink{userContactLinkId} memberRole = do DB.execute db "UPDATE user_contact_links SET group_link_member_role = ? WHERE user_id = ? AND user_contact_link_id = ?" (memberRole, userId, userContactLinkId) @@ -2038,33 +2030,6 @@ getRelayInactiveGroups db cxt User {userId, userContactId} ttl = do ) (userId, userContactId, RSInactive, cutoffTs) -createNewContactMemberAsync :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> Contact -> GroupMemberRole -> (CommandId, ConnId) -> VersionChat -> VersionRangeChat -> SubscriptionMode -> ExceptT StoreError IO () -createNewContactMemberAsync db gVar user@User {userId, userContactId} GroupInfo {groupId, membership} Contact {contactId, localDisplayName, profile} memberRole (cmdId, agentConnId) chatV peerChatVRange subMode = - createWithRandomId' db gVar $ \memId -> runExceptT $ do - createdAt <- liftIO getCurrentTime - insertMember_ (MemberId memId) createdAt - groupMemberId <- liftIO $ insertedRowId db - Connection {connId} <- liftIO $ createMemberConnection_ db userId groupMemberId agentConnId chatV peerChatVRange Nothing 0 createdAt subMode - liftIO $ setCommandConnId db user cmdId connId - where - VersionRange minV maxV = peerChatVRange - insertMember_ memberId createdAt = do - indexInGroup <- getUpdateNextIndexInGroup_ db groupId - liftIO $ - DB.execute - db - [sql| - INSERT INTO group_members - ( group_id, index_in_group, member_id, member_role, member_category, member_status, member_relations_vector, invited_by, invited_by_group_member_id, - user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at, - peer_chat_min_version, peer_chat_max_version) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) - |] - ( (groupId, indexInGroup, memberId, memberRole, GCInviteeMember, GSMemInvited, Binary B.empty, fromInvitedBy userContactId IBUser, groupMemberId' membership) - :. (userId, localDisplayName, contactId, localProfileId profile, createdAt, createdAt) - :. (minV, maxV) - ) - createJoiningMember :: DB.Connection -> StoreCxt -> TVar ChaChaDRG -> User -> GroupInfo -> VersionRangeChat -> Profile -> Maybe XContactId -> Maybe MemberId -> Maybe SharedMsgId -> GroupMemberRole -> GroupMemberStatus -> Maybe MemberKey -> ExceptT StoreError IO (GroupMemberId, MemberId) createJoiningMember db @@ -2224,11 +2189,6 @@ getContactViaMember db cxt user@User {userId} GroupMember {groupMemberId} = do (userId, groupMemberId) getContact db cxt user contactId -setNewContactMemberConnRequest :: DB.Connection -> User -> GroupMember -> ConnReqInvitation -> IO () -setNewContactMemberConnRequest db User {userId} GroupMember {groupMemberId} connRequest = do - currentTs <- getCurrentTime - DB.execute db "UPDATE group_members SET sent_inv_queue_info = ?, updated_at = ? WHERE user_id = ? AND group_member_id = ?" (connRequest, currentTs, userId, groupMemberId) - getMemberInvitation :: DB.Connection -> User -> Int64 -> IO (Maybe ConnReqInvitation) getMemberInvitation db User {userId} groupMemberId = fmap join . maybeFirstRow fromOnly $ diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt index 14e2299514..72903e7922 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt @@ -4767,13 +4767,6 @@ Query: Plan: -Query: - INSERT INTO chat_item_moderations - (group_id, moderator_member_id, item_member_id, shared_msg_id, created_by_msg_id, moderated_at) - VALUES (?,?,?,?,?,?) - -Plan: - Query: INSERT INTO chat_item_versions (chat_item_id, msg_content, item_version_ts) VALUES (?,?,?) @@ -6477,10 +6470,6 @@ Query: DELETE FROM chat_item_mentions WHERE chat_item_id = ? Plan: SEARCH chat_item_mentions USING COVERING INDEX idx_chat_item_mentions_chat_item_id (chat_item_id=?) -Query: DELETE FROM chat_item_moderations WHERE group_id = ? AND item_member_id = ? AND shared_msg_id = ? -Plan: -SEARCH chat_item_moderations USING COVERING INDEX idx_chat_item_moderations_group (group_id=? AND item_member_id=? AND shared_msg_id=?) - Query: DELETE FROM chat_item_reactions WHERE contact_id = ? Plan: SEARCH chat_item_reactions USING COVERING INDEX idx_chat_item_reactions_contact_id (contact_id=?) @@ -7170,6 +7159,10 @@ Plan: SCAN m USING COVERING INDEX idx_group_members_user_id_local_display_name SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) +Query: SELECT chat_item_id FROM chat_items WHERE group_scope_tag = 'member_support' ORDER BY chat_item_id DESC LIMIT 1 +Plan: +SCAN chat_items + Query: SELECT chat_item_id FROM chat_items WHERE item_text LIKE '%' || ? || '%' ORDER BY chat_item_id DESC LIMIT 1 Plan: SCAN chat_items diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs index dce1a2a9c9..63a3315d6d 100644 --- a/src/Simplex/Chat/Types.hs +++ b/src/Simplex/Chat/Types.hs @@ -2071,7 +2071,7 @@ instance TextEncoding CommandStatus where data CommandFunction = CFCreateConnGrpMemInv - | CFCreateConnGrpInv + | CFCreateConnGrpInv -- deprecated | CFCreateConnFileInvDirect -- deprecated | CFCreateConnFileInvGroup -- deprecated | CFJoinConn @@ -2204,7 +2204,7 @@ peerConnChatVersion _local@(VersionRange lmin lmax) _peer@(VersionRange rmin rma | otherwise = rmax initialChatVersion :: VersionChat -initialChatVersion = VersionChat 1 +initialChatVersion = VersionChat 9 chatInitialVRange :: VersionRangeChat chatInitialVRange = versionToRange initialChatVersion diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index 3cf7554cf5..bdc708b069 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -445,7 +445,6 @@ chatEventToView hu ChatConfig {logLevel, showReactions, showReceipts, testView} CEvtGroupChatItemsDeleted u g ciIds byUser member_ -> ttyUser u $ viewGroupChatItemsDeleted g ciIds byUser member_ CEvtChatItemDeletedNotFound u Contact {localDisplayName = c} _ -> ttyUser u [ttyFrom $ c <> "> [deleted - original message not found]"] CEvtUserAcceptedGroupSent u _g _ -> ttyUser u [] -- [ttyGroup' g <> ": joining the group..."] - CEvtSentGroupInvitation u g c _ -> ttyUser u $ viewSentGroupInvitation g c CEvtContactDeletedByContact u c -> ttyUser u [ttyFullContact c <> " deleted contact with you"] CEvtAcceptingContactRequest u c -> ttyUser u $ viewAcceptingContactRequest c CEvtAcceptingBusinessRequest u g -> ttyUser u $ viewAcceptingBusinessRequest g diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs index 77d91bf522..2e859dd68c 100644 --- a/tests/ChatClient.hs +++ b/tests/ChatClient.hs @@ -37,7 +37,6 @@ import Simplex.Chat.Library.Commands import Simplex.Chat.Operators import Simplex.Chat.Options import Simplex.Chat.Options.DB -import Simplex.Chat.Protocol (currentChatVersion, pqEncryptionCompressionVersion) import Simplex.Chat.Store import Simplex.Chat.Store.Profiles import Simplex.Chat.Terminal @@ -51,7 +50,7 @@ import Simplex.FileTransfer.Server.Store import Simplex.FileTransfer.Transport (alpnSupportedXFTPhandshakes, supportedFileServerVRange) import Simplex.Messaging.Agent (disposeAgentClient) import Simplex.Messaging.Agent.Env.SQLite -import Simplex.Messaging.Agent.Protocol (currentSMPAgentVersion, duplexHandshakeSMPAgentVersion, pqdrSMPAgentVersion, supportedSMPAgentVRange) +import Simplex.Messaging.Agent.Protocol (duplexHandshakeSMPAgentVersion, pqdrSMPAgentVersion, supportedSMPAgentVRange) import Simplex.Messaging.Agent.RetryInterval import Simplex.Messaging.Agent.Store.Entity (SDBStored (..)) import Simplex.Messaging.Agent.Store.Interface (closeDBStore) @@ -232,21 +231,12 @@ testAgentCfgVPrev = smpCfg = (smpCfg testAgentCfg) {serverVRange = prevRange $ serverVRange $ smpCfg testAgentCfg} } -testAgentCfgVNext :: AgentConfig -testAgentCfgVNext = - testAgentCfg - { smpClientVRange = nextRange $ smpClientVRange testAgentCfg, - smpAgentVRange = mkVersionRange duplexHandshakeSMPAgentVersion $ max pqdrSMPAgentVersion currentSMPAgentVersion, - e2eEncryptVRange = mkVersionRange CR.kdfX3DHE2EEncryptVersion $ max CR.pqRatchetE2EEncryptVersion CR.currentE2EEncryptVersion, - smpCfg = (smpCfg testAgentCfg) {serverVRange = nextRange $ serverVRange $ smpCfg testAgentCfg} - } - testAgentCfgV1 :: AgentConfig testAgentCfgV1 = testAgentCfg { smpClientVRange = v1Range, - smpAgentVRange = versionToRange duplexHandshakeSMPAgentVersion, - e2eEncryptVRange = versionToRange CR.kdfX3DHE2EEncryptVersion, + smpAgentVRange = mkVersionRange duplexHandshakeSMPAgentVersion pqdrSMPAgentVersion, + e2eEncryptVRange = mkVersionRange CR.kdfX3DHE2EEncryptVersion CR.pqRatchetE2EEncryptVersion, smpCfg = (smpCfg testAgentCfg) {serverVRange = versionToRange minClientSMPRelayVersion} } @@ -257,17 +247,10 @@ testCfgVPrev = agentConfig = testAgentCfgVPrev } -testCfgVNext :: ChatConfig -testCfgVNext = - testCfg - { chatVRange = mkVersionRange initialChatVersion $ max pqEncryptionCompressionVersion currentChatVersion, - agentConfig = testAgentCfgVNext - } - testCfgV1 :: ChatConfig testCfgV1 = testCfg - { chatVRange = v1Range, + { chatVRange = chatInitialVRange, agentConfig = testAgentCfgV1 } diff --git a/tests/ChatTests/Direct.hs b/tests/ChatTests/Direct.hs index e34f071fd0..f37587164b 100644 --- a/tests/ChatTests/Direct.hs +++ b/tests/ChatTests/Direct.hs @@ -3323,17 +3323,17 @@ testUpdatePeerChatVRange ps = cfg11 = testCfg {chatVRange = vr11} :: ChatConfig vr11 :: VersionRangeChat -vr11 = mkVersionRange (VersionChat 1) (VersionChat 1) +vr11 = mkVersionRange (VersionChat 9) (VersionChat 9) contactInfoChatVRange :: TestCC -> VersionRangeChat -> IO () -contactInfoChatVRange cc (VersionRange minVer maxVer) = do +contactInfoChatVRange cc vr = do cc <## "contact ID: 2" cc <## "receiving messages via: localhost" cc <## "sending messages via: localhost" cc <## "you've shared main profile with this contact" cc <## "connection not verified, use /code command to see security code" cc <## "quantum resistant end-to-end encryption" - cc <## ("peer chat protocol version range: (" <> show minVer <> ", " <> show maxVer <> ")") + cc <## ("peer chat protocol version range: " <> vRangeStr vr) testLinkContentFilter :: HasCallStack => TestParams -> IO () testLinkContentFilter = diff --git a/tests/ChatTests/Groups.hs b/tests/ChatTests/Groups.hs index 37827ab2ad..684655c946 100644 --- a/tests/ChatTests/Groups.hs +++ b/tests/ChatTests/Groups.hs @@ -97,8 +97,8 @@ chatGroupTests = do it "moderate own message (should process as deletion)" testGroupModerateOwn it "moderate multiple messages" testGroupModerateMultiple it "moderate message of another group member (full delete)" testGroupModerateFullDelete - it "moderate message that arrives after the event of moderation" testGroupDelayedModeration - it "moderate message that arrives after the event of moderation (full delete)" testGroupDelayedModerationFullDelete + xit "moderate message that arrives after the event of moderation" testGroupDelayedModeration + xit "moderate message that arrives after the event of moderation (full delete)" testGroupDelayedModerationFullDelete it "remove member with messages (full deletion is enabled)" testDeleteMemberWithMessages it "remove member with messages mark deleted" testDeleteMemberMarkMessagesDeleted it "remove member - delete messages of left/removed members" testDeleteMemberMessagesLeftRemoved @@ -2990,7 +2990,7 @@ testGroupLinkMemberRole = bob <## "#team: you joined the group" ] - threadDelay 100000 + threadDelay 250000 alice ##> "/ms team" alice diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index 4b82779b0e..c9f3864a82 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -26,7 +26,7 @@ import qualified Data.Map.Strict as M import Simplex.Chat.Badges (BadgeCredential, BadgeInfo (..), BadgePurchase (..), BadgeRequest (..), BadgeType (..), generateMasterKey, issueBadge, verifyPayment) import Simplex.Chat.Controller (ChatConfig (..), ChatController (..), ChatHooks (..), defaultChatHooks, mkStoreCxt) import Simplex.Chat.Options (ChatOpts (..), CoreChatOpts (..)) -import Simplex.Chat.Protocol (LinkOwnerSig, MsgChatLink (..), MsgContent (..), currentChatVersion) +import Simplex.Chat.Protocol (LinkOwnerSig, MsgChatLink (..), MsgContent (..)) import Simplex.Chat.Store.Shared (createContact) import Simplex.Chat.Types (ConnStatus (..), Profile (..), GroupRejectionReason (..), profileFromName) import qualified Simplex.Messaging.Crypto as C @@ -3040,7 +3040,7 @@ testSetUITheme = a <## "you've shared main profile with this contact" a <## "connection not verified, use /code command to see security code" a <## "quantum resistant end-to-end encryption" - a <## ("peer chat protocol version range: (Version 1, " <> show currentChatVersion <> ")") + a <## currentChatVRangeInfo groupInfo a = do a <## "group ID: 1" a <## "current members: 1" diff --git a/tests/ChatTests/Utils.hs b/tests/ChatTests/Utils.hs index df2bff8ab6..805c3bd155 100644 --- a/tests/ChatTests/Utils.hs +++ b/tests/ChatTests/Utils.hs @@ -127,9 +127,9 @@ versionTestMatrix2 runTest = do it "prev" $ runTestCfg2 testCfgVPrev testCfgVPrev (runTest False True) it "prev to curr" $ runTestCfg2 testCfg testCfgVPrev (runTest False True) it "curr to prev" $ runTestCfg2 testCfgVPrev testCfg (runTest False True) - it "old (1st supported)" $ testChatCfg2 testCfgV1 aliceProfile bobProfile (runTest False False) - it "old to curr" $ runTestCfg2 testCfg testCfgV1 (runTest False True) - it "curr to old" $ runTestCfg2 testCfgV1 testCfg (runTest False False) + it "old (1st supported)" $ testChatCfg2 testCfgV1 aliceProfile bobProfile (runTest True False) + it "old to curr" $ runTestCfg2 testCfg testCfgV1 (runTest True True) + it "curr to old" $ runTestCfg2 testCfgV1 testCfg (runTest True False) versionTestMatrix3 :: (HasCallStack => TestCC -> TestCC -> TestCC -> IO ()) -> SpecWith TestParams versionTestMatrix3 runTest = do diff --git a/tests/ProtocolTests.hs b/tests/ProtocolTests.hs index 798ab3c4d7..d64ab82d23 100644 --- a/tests/ProtocolTests.hs +++ b/tests/ProtocolTests.hs @@ -135,64 +135,64 @@ shortLinkDataTests = describe "Short link data encoding/decoding" $ do decodeChatMessageTest :: Spec decodeChatMessageTest = describe "Chat message encoding/decoding" $ do it "x.msg.new simple text" $ - "{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" + "{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" #==# XMsgNew (mcSimple (MCText "hello")) it "x.msg.new simple text - timed message TTL" $ - "{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"ttl\":3600}}" + "{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"ttl\":3600}}" #==# XMsgNew ((mcSimple (MCText "hello")) {ttl = Just 3600}) it "x.msg.new simple text - live message" $ - "{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"live\":true}}" + "{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"live\":true}}" #==# XMsgNew ((mcSimple (MCText "hello")) {live = Just True}) it "x.msg.new simple link" $ - "{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"https://simplex.chat\",\"type\":\"link\",\"preview\":{\"description\":\"SimpleX Chat\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgA\",\"title\":\"SimpleX Chat\",\"uri\":\"https://simplex.chat\"}}}}" + "{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"https://simplex.chat\",\"type\":\"link\",\"preview\":{\"description\":\"SimpleX Chat\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgA\",\"title\":\"SimpleX Chat\",\"uri\":\"https://simplex.chat\"}}}}" #==# XMsgNew (mcSimple (MCLink "https://simplex.chat" $ LinkPreview {uri = "https://simplex.chat", title = "SimpleX Chat", description = "SimpleX Chat", image = ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgA", content = Nothing})) it "x.msg.new simple image" $ - "{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}}" + "{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}}" #==# XMsgNew (mcSimple (MCImage "" $ ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=")) it "x.msg.new simple image with text" $ - "{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"here's an image\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}}" + "{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"here's an image\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}}" #==# XMsgNew (mcSimple (MCImage "here's an image" $ ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=")) it "x.msg.new chat message" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew (mcSimple (MCText "hello"))) it "x.msg.new chat message with chat version range" $ - "{\"v\":\"1-19\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" + "{\"v\":\"9-19\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" ##==## ChatMessage supportedChatVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew (mcSimple (MCText "hello"))) it "x.msg.new quote" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello to you too\",\"type\":\"text\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}}}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello to you too\",\"type\":\"text\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}}}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew (mcQuote quotedMsg (MCText "hello to you too"))) it "x.msg.new quote - timed message TTL" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello to you too\",\"type\":\"text\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}},\"ttl\":3600}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello to you too\",\"type\":\"text\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}},\"ttl\":3600}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew ((mcQuote quotedMsg (MCText "hello to you too")) {ttl = Just 3600})) it "x.msg.new quote - live message" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello to you too\",\"type\":\"text\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}},\"live\":true}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello to you too\",\"type\":\"text\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}},\"live\":true}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew ((mcQuote quotedMsg (MCText "hello to you too")) {live = Just True})) it "x.msg.new forward" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"forward\":true}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"forward\":true}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew $ mcForward (MCText "hello")) it "x.msg.new forward - timed message TTL" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"forward\":true,\"ttl\":3600}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"forward\":true,\"ttl\":3600}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew $ (mcForward (MCText "hello")) {ttl = Just 3600}) it "x.msg.new forward - live message" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"forward\":true,\"live\":true}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"forward\":true,\"live\":true}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew $ (mcForward (MCText "hello")) {live = Just True}) it "x.msg.new simple text with file" $ - "{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}" + "{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}" #==# XMsgNew ((mcSimple (MCText "hello")) {file = Just FileInvitation {fileName = "photo.jpg", fileSize = 12345, fileDigest = Nothing, fileConnReq = Nothing, fileInline = Nothing, fileDescr = Nothing}}) it "x.msg.new simple file with file" $ - "{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"\",\"type\":\"file\"},\"file\":{\"fileSize\":12345,\"fileName\":\"file.txt\"}}}" + "{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"\",\"type\":\"file\"},\"file\":{\"fileSize\":12345,\"fileName\":\"file.txt\"}}}" #==# XMsgNew ((mcSimple (MCFile "")) {file = Just FileInvitation {fileName = "file.txt", fileSize = 12345, fileDigest = Nothing, fileConnReq = Nothing, fileInline = Nothing, fileDescr = Nothing}}) it "x.msg.new quote with file" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello to you too\",\"type\":\"text\"},\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}}}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello to you too\",\"type\":\"text\"},\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}}}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") @@ -201,134 +201,134 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do {file = Just FileInvitation {fileName = "photo.jpg", fileSize = 12345, fileDigest = Nothing, fileConnReq = Nothing, fileInline = Nothing, fileDescr = Nothing}} ) it "x.msg.new report" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"\",\"reason\":\"spam\",\"type\":\"report\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}}}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"\",\"reason\":\"spam\",\"type\":\"report\"},\"quote\":{\"content\":{\"text\":\"hello there!\",\"type\":\"text\"},\"msgRef\":{\"msgId\":\"BQYHCA==\",\"sent\":true,\"sentAt\":\"1970-01-01T00:00:01.000000001Z\"}}}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew (mcQuote quotedMsg (MCReport "" RRSpam))) it "x.msg.new forward with file" $ - "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"},\"forward\":true}}" + "{\"v\":\"9\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"},\"forward\":true}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew $ (mcForward (MCText "hello")) {file = Just FileInvitation {fileName = "photo.jpg", fileSize = 12345, fileDigest = Nothing, fileConnReq = Nothing, fileInline = Nothing, fileDescr = Nothing}}) it "x.msg.update" $ - "{\"v\":\"1\",\"event\":\"x.msg.update\",\"params\":{\"msgId\":\"AQIDBA==\", \"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" + "{\"v\":\"9\",\"event\":\"x.msg.update\",\"params\":{\"msgId\":\"AQIDBA==\", \"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" #==# XMsgUpdate (SharedMsgId "\1\2\3\4") (MCText "hello") [] Nothing Nothing Nothing Nothing it "x.msg.del" $ - "{\"v\":\"1\",\"event\":\"x.msg.del\",\"params\":{\"msgId\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.msg.del\",\"params\":{\"msgId\":\"AQIDBA==\"}}" #==# XMsgDel (SharedMsgId "\1\2\3\4") Nothing Nothing False it "x.msg.deleted" $ - "{\"v\":\"1\",\"event\":\"x.msg.deleted\",\"params\":{}}" + "{\"v\":\"9\",\"event\":\"x.msg.deleted\",\"params\":{}}" #==# XMsgDeleted it "x.file" $ - "{\"v\":\"1\",\"event\":\"x.file\",\"params\":{\"file\":{\"fileConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}" + "{\"v\":\"9\",\"event\":\"x.file\",\"params\":{\"file\":{\"fileConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}" #==# XFile FileInvitation {fileName = "photo.jpg", fileSize = 12345, fileDigest = Nothing, fileConnReq = Just testConnReq, fileInline = Nothing, fileDescr = Nothing} it "x.file without file invitation" $ - "{\"v\":\"1\",\"event\":\"x.file\",\"params\":{\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}" + "{\"v\":\"9\",\"event\":\"x.file\",\"params\":{\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}" #==# XFile FileInvitation {fileName = "photo.jpg", fileSize = 12345, fileDigest = Nothing, fileConnReq = Nothing, fileInline = Nothing, fileDescr = Nothing} it "x.file.acpt" $ - "{\"v\":\"1\",\"event\":\"x.file.acpt\",\"params\":{\"fileName\":\"photo.jpg\"}}" + "{\"v\":\"9\",\"event\":\"x.file.acpt\",\"params\":{\"fileName\":\"photo.jpg\"}}" #==# XFileAcpt "photo.jpg" it "x.file.acpt.inv" $ - "{\"v\":\"1\",\"event\":\"x.file.acpt.inv\",\"params\":{\"msgId\":\"AQIDBA==\",\"fileName\":\"photo.jpg\",\"fileConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}" + "{\"v\":\"9\",\"event\":\"x.file.acpt.inv\",\"params\":{\"msgId\":\"AQIDBA==\",\"fileName\":\"photo.jpg\",\"fileConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}" #==# XFileAcptInv (SharedMsgId "\1\2\3\4") (Just testConnReq) "photo.jpg" it "x.file.acpt.inv" $ - "{\"v\":\"1\",\"event\":\"x.file.acpt.inv\",\"params\":{\"msgId\":\"AQIDBA==\",\"fileName\":\"photo.jpg\"}}" + "{\"v\":\"9\",\"event\":\"x.file.acpt.inv\",\"params\":{\"msgId\":\"AQIDBA==\",\"fileName\":\"photo.jpg\"}}" #==# XFileAcptInv (SharedMsgId "\1\2\3\4") Nothing "photo.jpg" it "x.file.cancel" $ - "{\"v\":\"1\",\"event\":\"x.file.cancel\",\"params\":{\"msgId\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.file.cancel\",\"params\":{\"msgId\":\"AQIDBA==\"}}" #==# XFileCancel (SharedMsgId "\1\2\3\4") it "x.info" $ - "{\"v\":\"1\",\"event\":\"x.info\",\"params\":{\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" + "{\"v\":\"9\",\"event\":\"x.info\",\"params\":{\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" #==# XInfo testProfile it "x.info with empty full name" $ - "{\"v\":\"1\",\"event\":\"x.info\",\"params\":{\"profile\":{\"fullName\":\"\",\"displayName\":\"alice\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" + "{\"v\":\"9\",\"event\":\"x.info\",\"params\":{\"profile\":{\"fullName\":\"\",\"displayName\":\"alice\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" #==# XInfo Profile {displayName = "alice", fullName = "", shortDescr = Nothing, description = Nothing, image = Nothing, contactLink = Nothing, peerType = Nothing, preferences = testChatPreferences, badge = Nothing, contactDomain = Nothing} it "x.contact with xContactId" $ - "{\"v\":\"1\",\"event\":\"x.contact\",\"params\":{\"contactReqId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" + "{\"v\":\"9\",\"event\":\"x.contact\",\"params\":{\"contactReqId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" #==# XContact testProfile (Just $ XContactId "\1\2\3\4") Nothing Nothing it "x.contact without XContactId" $ - "{\"v\":\"1\",\"event\":\"x.contact\",\"params\":{\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" + "{\"v\":\"9\",\"event\":\"x.contact\",\"params\":{\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" #==# XContact testProfile Nothing Nothing Nothing it "x.contact with content null" $ - "{\"v\":\"1\",\"event\":\"x.contact\",\"params\":{\"content\":null,\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" + "{\"v\":\"9\",\"event\":\"x.contact\",\"params\":{\"content\":null,\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" ==# XContact testProfile Nothing Nothing Nothing it "x.contact with content" $ - "{\"v\":\"1\",\"event\":\"x.contact\",\"params\":{\"msgId\":\"AQIDBA==\",\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" + "{\"v\":\"9\",\"event\":\"x.contact\",\"params\":{\"msgId\":\"AQIDBA==\",\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" ==# XContact testProfile Nothing Nothing (Just (SharedMsgId "\1\2\3\4", MCText {text = "hello"})) it "x.grp.inv" $ - "{\"v\":\"1\",\"event\":\"x.grp.inv\",\"params\":{\"groupInvitation\":{\"connRequest\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"invitedMember\":{\"memberRole\":\"member\",\"memberId\":\"BQYHCA==\"},\"groupProfile\":{\"fullName\":\"Team\",\"displayName\":\"team\",\"groupPreferences\":{\"reactions\":{\"enable\":\"on\"},\"voice\":{\"enable\":\"on\"}}},\"fromMember\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\"}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.inv\",\"params\":{\"groupInvitation\":{\"connRequest\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"invitedMember\":{\"memberRole\":\"member\",\"memberId\":\"BQYHCA==\"},\"groupProfile\":{\"fullName\":\"Team\",\"displayName\":\"team\",\"groupPreferences\":{\"reactions\":{\"enable\":\"on\"},\"voice\":{\"enable\":\"on\"}}},\"fromMember\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\"}}}}" #==# XGrpInv GroupInvitation {fromMember = MemberIdRole (MemberId "\1\2\3\4") GRAdmin, invitedMember = MemberIdRole (MemberId "\5\6\7\8") GRMember, connRequest = testConnReq, groupProfile = testGroupProfile, business = Nothing, groupLinkId = Nothing, groupSize = Nothing} it "x.grp.inv with group link id" $ - "{\"v\":\"1\",\"event\":\"x.grp.inv\",\"params\":{\"groupInvitation\":{\"connRequest\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"invitedMember\":{\"memberRole\":\"member\",\"memberId\":\"BQYHCA==\"},\"groupProfile\":{\"fullName\":\"Team\",\"displayName\":\"team\",\"groupPreferences\":{\"reactions\":{\"enable\":\"on\"},\"voice\":{\"enable\":\"on\"}}},\"fromMember\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\"}, \"groupLinkId\":\"AQIDBA==\"}}}" + "{\"v\":\"9\",\"event\":\"x.grp.inv\",\"params\":{\"groupInvitation\":{\"connRequest\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"invitedMember\":{\"memberRole\":\"member\",\"memberId\":\"BQYHCA==\"},\"groupProfile\":{\"fullName\":\"Team\",\"displayName\":\"team\",\"groupPreferences\":{\"reactions\":{\"enable\":\"on\"},\"voice\":{\"enable\":\"on\"}}},\"fromMember\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\"}, \"groupLinkId\":\"AQIDBA==\"}}}" #==# XGrpInv GroupInvitation {fromMember = MemberIdRole (MemberId "\1\2\3\4") GRAdmin, invitedMember = MemberIdRole (MemberId "\5\6\7\8") GRMember, connRequest = testConnReq, groupProfile = testGroupProfile, business = Nothing, groupLinkId = Just $ GroupLinkId "\1\2\3\4", groupSize = Nothing} it "x.grp.acpt without incognito profile" $ - "{\"v\":\"1\",\"event\":\"x.grp.acpt\",\"params\":{\"memberId\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.grp.acpt\",\"params\":{\"memberId\":\"AQIDBA==\"}}" #==# XGrpAcpt (MemberId "\1\2\3\4") it "x.grp.mem.new" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.new\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.new\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" #==# XGrpMemNew MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Nothing, profile = testProfile, memberKey = Nothing} Nothing it "x.grp.mem.new with member chat version range" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.new\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-19\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.new\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"9-19\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" #==# XGrpMemNew MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Just $ ChatVersionRange supportedChatVRange, profile = testProfile, memberKey = Nothing} Nothing it "x.grp.mem.intro" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.intro\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.intro\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" #==# XGrpMemIntro MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Nothing, profile = testProfile, memberKey = Nothing} Nothing it "x.grp.mem.intro with member chat version range" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.intro\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-19\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.intro\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"9-19\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" #==# XGrpMemIntro MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Just $ ChatVersionRange supportedChatVRange, profile = testProfile, memberKey = Nothing} Nothing it "x.grp.mem.intro with member restrictions" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.intro\",\"params\":{\"memberRestrictions\":{\"restriction\":\"blocked\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.intro\",\"params\":{\"memberRestrictions\":{\"restriction\":\"blocked\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" #==# XGrpMemIntro MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Nothing, profile = testProfile, memberKey = Nothing} (Just MemberRestrictions {restriction = MRSBlocked}) it "x.grp.mem.inv" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.inv\",\"params\":{\"memberId\":\"AQIDBA==\",\"memberIntro\":{\"directConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.inv\",\"params\":{\"memberId\":\"AQIDBA==\",\"memberIntro\":{\"directConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}" #==# XGrpMemInv (MemberId "\1\2\3\4") IntroInvitation {groupConnReq = testConnReq, directConnReq = Just testConnReq} it "x.grp.mem.inv w/t directConnReq" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.inv\",\"params\":{\"memberId\":\"AQIDBA==\",\"memberIntro\":{\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.inv\",\"params\":{\"memberId\":\"AQIDBA==\",\"memberIntro\":{\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}" #==# XGrpMemInv (MemberId "\1\2\3\4") IntroInvitation {groupConnReq = testConnReq, directConnReq = Nothing} it "x.grp.mem.fwd" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.fwd\",\"params\":{\"memberIntro\":{\"directConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.fwd\",\"params\":{\"memberIntro\":{\"directConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" #==# XGrpMemFwd MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Nothing, profile = testProfile, memberKey = Nothing} IntroInvitation {groupConnReq = testConnReq, directConnReq = Just testConnReq} it "x.grp.mem.fwd with member chat version range and w/t directConnReq" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.fwd\",\"params\":{\"memberIntro\":{\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-19\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.fwd\",\"params\":{\"memberIntro\":{\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"9-19\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" #==# XGrpMemFwd MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Just $ ChatVersionRange supportedChatVRange, profile = testProfile, memberKey = Nothing} IntroInvitation {groupConnReq = testConnReq, directConnReq = Nothing} it "x.grp.mem.info" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.info\",\"params\":{\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.info\",\"params\":{\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}" #==# XGrpMemInfo (MemberId "\1\2\3\4") testProfile it "x.grp.mem.con" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.con\",\"params\":{\"memberId\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.con\",\"params\":{\"memberId\":\"AQIDBA==\"}}" #==# XGrpMemCon (MemberId "\1\2\3\4") it "x.grp.mem.con.all" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.con.all\",\"params\":{\"memberId\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.con.all\",\"params\":{\"memberId\":\"AQIDBA==\"}}" #==# XGrpMemConAll (MemberId "\1\2\3\4") it "x.grp.mem.del" $ - "{\"v\":\"1\",\"event\":\"x.grp.mem.del\",\"params\":{\"memberId\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.grp.mem.del\",\"params\":{\"memberId\":\"AQIDBA==\"}}" #==# XGrpMemDel (MemberId "\1\2\3\4") False Nothing it "x.grp.leave" $ - "{\"v\":\"1\",\"event\":\"x.grp.leave\",\"params\":{}}" + "{\"v\":\"9\",\"event\":\"x.grp.leave\",\"params\":{}}" ==# XGrpLeave it "x.grp.del" $ - "{\"v\":\"1\",\"event\":\"x.grp.del\",\"params\":{}}" + "{\"v\":\"9\",\"event\":\"x.grp.del\",\"params\":{}}" ==# XGrpDel it "x.grp.direct.inv" $ - "{\"v\":\"1\",\"event\":\"x.grp.direct.inv\",\"params\":{\"connReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\", \"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" + "{\"v\":\"9\",\"event\":\"x.grp.direct.inv\",\"params\":{\"connReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\", \"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" #==# XGrpDirectInv testConnReq (Just $ MCText "hello") Nothing it "x.grp.direct.inv without content" $ - "{\"v\":\"1\",\"event\":\"x.grp.direct.inv\",\"params\":{\"connReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}" + "{\"v\":\"9\",\"event\":\"x.grp.direct.inv\",\"params\":{\"connReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2-3%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}" #==# XGrpDirectInv testConnReq Nothing Nothing -- it "x.grp.msg.forward" - -- $ "{\"v\":\"1\",\"event\":\"x.grp.msg.forward\",\"params\":{\"msgForward\":{\"memberId\":\"AQIDBA==\",\"msg\":\"{\"v\":\"1\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}\",\"msgTs\":\"1970-01-01T00:00:01.000000001Z\"}}}" + -- $ "{\"v\":\"9\",\"event\":\"x.grp.msg.forward\",\"params\":{\"msgForward\":{\"memberId\":\"AQIDBA==\",\"msg\":\"{\"v\":\"9\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}\",\"msgTs\":\"1970-01-01T00:00:01.000000001Z\"}}}" -- #==# XGrpMsgForward -- (MemberId "\1\2\3\4") -- (ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew (mcSimple (MCText "hello")))) -- (systemToUTCTime $ MkSystemTime 1 1) it "x.info.probe" $ - "{\"v\":\"1\",\"event\":\"x.info.probe\",\"params\":{\"probe\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.info.probe\",\"params\":{\"probe\":\"AQIDBA==\"}}" #==# XInfoProbe (Probe "\1\2\3\4") it "x.info.probe.check" $ - "{\"v\":\"1\",\"event\":\"x.info.probe.check\",\"params\":{\"probeHash\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.info.probe.check\",\"params\":{\"probeHash\":\"AQIDBA==\"}}" #==# XInfoProbeCheck (ProbeHash "\1\2\3\4") it "x.info.probe.ok" $ - "{\"v\":\"1\",\"event\":\"x.info.probe.ok\",\"params\":{\"probe\":\"AQIDBA==\"}}" + "{\"v\":\"9\",\"event\":\"x.info.probe.ok\",\"params\":{\"probe\":\"AQIDBA==\"}}" #==# XInfoProbeOk (Probe "\1\2\3\4") it "x.ok" $ - "{\"v\":\"1\",\"event\":\"x.ok\",\"params\":{}}" + "{\"v\":\"9\",\"event\":\"x.ok\",\"params\":{}}" ==# XOk